访问父级的受保护变量

Posted

技术标签:

【中文标题】访问父级的受保护变量【英文标题】:Accessing parent's protected variables 【发布时间】:2011-06-17 07:15:50 【问题描述】:

我想不出更好的标题措辞,所以有点误导,但是,我不是在说孩子访问从其父级继承的变量,这很容易。

我说的是这个:

class Parent 
  protected:
     Parent *target;
     int hp;


class Child : public Parent 
  public:
     void my_func();


void Child::my_func() 
    target->hp -= 50;

但是,如果我尝试编译它,它会抱怨“hp”是“在这种情况下是私有的”。问题是孩子不是试图访问它自己的父母的变量,而是其他一些类,它可能是也可能不是孩子本身。

一个对象可以访问同一个类的另一个对象(内存中的两个独立实例)的所有变量和方法(公共的、受保护的或私有的),所以我认为它也可以使用它,因为它继承自它试图访问其变量的类,但我的假设似乎是不正确的。

有什么建议吗?

附:不要粗鲁或任何事情,但我知道我可以创建 get() 和 set() 方法,但我希望有一种更清洁的方法。

【问题讨论】:

这里写的代码中有很多错误(class 关键字大写不正确,继承语法不正确等),我确信这些错误不在原始代码中。获取一个无法编译的最小示例,然后将确切的代码复制并粘贴到此处可能会很有用。 @Tim 我以为你在那里和自己对话了一分钟,直到我比较了个人资料 是的,我应该为此做点什么。它并不像我想象的那样独特。 :-) 呃,是的,我并没有真正关注这一点,现在也不让我编辑它......编辑:我们走了。 @Abe:我遇到了同样的问题。幸好两者之一是OP,所以我的FF突出了他的名字。不过,这是一团糟。 【参考方案1】:

这很容易(意味着对 OP 的明显误解,是因为人们没有花时间阅读 OP)。

您只需让孩子成为您需要访问的父母变量的朋友。

或者,您可以让孩子成为父类的朋友。

这样任何孩子都可以访问任何父母的成员变量,这正是您所期望的。

class Child;

class Parent 
  protected:
     Parent *target;
     int hp;
     friend void Child::my_func();


class Child : public Parent 
  public:
     void my_func();


void Child::my_func() 
    target->hp -= 50;

这样做的缺点是每个孩子都可以访问每个父母的变量。但是,您必须考虑到,在您的情况下,编译器无法知道 Parent *target 是与子实例相同的实例。鉴于您将其命名为目标,我希望让每个孩子都可以访问每个父母的变量是您想要的。

这是另一种可能性。让其他人使用接口来访问父类,并且只有您的孩子使用实际的父类。结果是一样的。每个孩子都可以访问每个父母的变量。

您将类与实例混淆了。 子类可以访问相同 INSTANCE 的基类的相同成员变量。

【讨论】:

你不能让一个类成为变量的朋友。你的意思是说“类”吗? 在 Charles 的回答中也请注意我的 cmets。我对protected 所说的对friend 更是如此:它突破了类的抽象,将朋友与类的实现紧密耦合。紧耦合总是不好的。尽可能多地使用friend,但尽可能少。 复制粘贴:是的,我可以这样做,这就是我目前的技巧,但它似乎打破了继承的“向下”。您不需要为每个继承自它的类加好友才能使其正常工作。 好了,完成了。很难找到与您想要的完全匹配的示例。这就是你如何让一个班级的单一方法成为另一个班级的朋友。 您不能声明 classfriend 的成员,除非该类已经具有可见定义,包括相关成员的声明。如果您尝试授予访问权限的类将派生自尝试授予访问权限的类,这是不可能的。【参考方案2】:

特定类的成员函数只能访问基类的受保护成员,这些成员实际上是它们自己的类类型(或更多派生类型)对象的基类子对象。

一个类的成员无权访问该基类的其他实例的受保护成员,因此也禁止通过对基类类型的引用或指针访问受保护成员,即使在运行时该指针或引用可能是到其成员函数正在尝试访问的类的类型的对象。访问控制在编译时强制执行。

例如

class X

protected:
    int z;
;

class Y : X

public:
    int f( const Y& y )
    
        return y.z; // OK
    

    int g( const X& x )
    
        return x.z; // Error, Y::g has no access to X::z
    
;

在您的示例中,在表达式target->hp 中,对target 的访问是合法的,因为您正在访问当前对象的成员(该对象具有该函数所属的类的类型,@987654325 @),但是访问成员hp是不合法的,因为target的类型不是指向Child的指针,而是指向Parent的指针。

【讨论】:

也许我在 OP 中说得不够清楚,但我明白这一点。我想知道是否有任何方法可以在没有 get() 和 set() 方法的情况下做到这一点。 @Tim:我的回答是试图帮助解释您的错误假设。存在滥用,但您应该修复类层次结构,以便您拥有所需的访问权限。 ***.com/questions/3364722/… 在这种(简化的)案例中,我将如何修复类层次结构? @Tim:显而易见的解决方案是公开hp,因为这是您需要的访问权限。 @Tim:公共数据不受欢迎是有充分理由的,受保护的数据只是对派生类公开的数据。在我用 C++ 编程超过 15 年的时间里,我偶尔需要它,但在过去十年中很少需要它。一个类的状态(数据)应该通过它的成员函数来操作,而不是直接摆弄。如果我遇到这种需求,我会问自己基类应该代表什么抽象,以及为什么派生类需要突破这种抽象并直接访问基类的数据。【参考方案3】:

嗯,奇怪的是到目前为止没有人提到这一点,但你可以声明 Child 是 Parent 的朋友(可能是因为你的代码不太清楚你想在这里做什么)

class Parent 
  friend class Child;
  protected:
     int hp;


class Child 
  public:
     void my_func();
     Parent *target;

这将允许访问。或者,您可以编写一个公开的访问器方法:

class Parent 
public:
  get_hp()return hp;
protected:
  int hp;

【讨论】:

是的,我可以这样做,这就是我目前的技巧,但它似乎打破了继承的“向下”。您不需要为每个继承自它的类加好友才能使其正常工作。 另外,正如我所说,我知道我可以只使用 set() 和 get() 方法,这就是您的示例。我想看看是否有任何类似于我正在尝试的方式的方法,如果您不使用继承,您将能够做到。 @Tim:正如我在对 Charles 的回答的评论中所说,问题是您想要突破基类所代表的抽象。你需要问问自己为什么要这样做。【参考方案4】:

试着改成这个

 Class Child : public Parent

【讨论】:

公共继承也会出现同样的问题。 这与Child 是从Parent 公开还是私下继承无关,而是Child 方法是否试图访问作为基类的Parent 的受保护成员Child 的子对象或不是的子对象。

以上是关于访问父级的受保护变量的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能访问子类中的受保护变量?

我们可以在父类的帮助下访问不同包中的受保护变量吗?

如何在同一个类的静态方法中访问类的受保护变量?

从嵌套类的函数访问父级的非静态成员

Java中的间接子类无法访问的超类中的受保护成员

获取父级的高度