You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:05:13