Unity继承类重写函数时变量访问权限问题求助
解决继承类重写函数时无法访问父类私有变量的问题
问题场景
在Unity中实现继承体系时,子类重写父类的虚函数后,尝试访问父类中的变量时触发错误:Variable is inaccessible due to its protection level。核心需求是让子类重写的函数能正常访问所需的变量(无论是父类的可继承变量,还是子类自身的变量)。
核心原因
C#的访问修饰符规则:private修饰的成员仅能在定义它的类内部访问,子类即便继承了该类,也无权直接访问父类的私有成员——这就是报错的根本原因。
解决方案
1. 将父类私有成员改为protected修饰(推荐)
protected是继承场景下的最优选择:它允许父类自身、所有子类访问成员,同时对外保持私有性,兼顾封装性和继承需求。
修改简化示例的父类:
public class InheritedClass : MonoBehaviour { // 将public改为protected,子类可访问,外部不可直接修改 protected int x; public virtual void Divideby2(int num) { Debug.Log(num/2); } }
子类Inheritor2可正常访问x:
如果需要子类拥有独立的x实例,可直接在子类中赋值,无需重新定义(若要覆盖父类的x,可使用new关键字):
public class Inheritor2 : InheritedClass { // 可选:定义子类专属的x(用new隐藏父类的x) // protected new int x = 3; public override void DivideBy2(int num) { Debug.Log(num/x); } }
修改实际代码的父类Weapon:
把所有需要被子类访问的private变量改为protected:
public class Weapon : MonoBehaviour { public GameObject AttackPrefab, SpecialPrefab, ThisWeaponPrefab, AttackSequenceFinisherPrefab; protected Vector3 MousePosition; [SerializeField] protected float SpecialCooldown, AttackCooldown, FinisherCooldown, AttackSequenceTimeToEnd; protected float TimePassed, RotationY, TimeToHold, AttackSequenceEndTime, SpecialCooldownTimer, FinisherCooldownTimer; public int MaxAttackSequence; [HideInInspector] public int AttackSequence; protected bool CanSpecial, CanAttack; public virtual void AttackDetermine(int num) { MousePosition = Input.mousePosition; if (MousePosition.x < 0) {MousePosition.x = 0;} if (MousePosition.x > Screen.width) {MousePosition.x = Screen.width;} if (MousePosition.y < 0) {MousePosition.x = 0;} if (MousePosition.y > Screen.height) {MousePosition.x = Screen.height;} MousePosition.y -= (Screen.height / 2); MousePosition.x -= (Screen.width / 2); RotationY = Mathf.Atan2(MousePosition.y, MousePosition.x) * Mathf.Rad2Deg - 90; if ((num == 2) & (Character.instance.BusyTime <= 0) & (SpecialCooldownTimer >= 0)){ CanSpecial = true; } else if ((num == 1) & (Character.instance.BusyTime <= 0) & (FinisherCooldownTimer <= 0)) { CanAttack = true; } } }
修改后,子类Bow的重写函数无需改动即可正常访问这些变量。
2. 为父类私有成员添加属性访问器
如果不想修改成员的原始访问修饰符,可以通过get/set属性让子类间接访问父类私有成员:
public class Weapon : MonoBehaviour { private Vector3 MousePosition; // 添加受保护属性,子类通过该属性访问私有变量 protected Vector3 MousePos { get => MousePosition; set => MousePosition = value; } // 其他需要访问的私有成员同理,添加对应的protected属性 }
子类中使用MousePos替代MousePosition即可完成访问。
额外提示
- 子类继承的
protected变量,每个实例都会拥有独立的副本,无需在子类中重新定义同名变量(除非有特殊的覆盖需求)。 - 尽量避免滥用
public修饰符,protected能在满足继承需求的同时,保证类内部状态不被外部随意修改,符合面向对象的封装原则。
内容的提问来源于stack exchange,提问作者Eutopia
相关产品推荐
相关产品推荐

