访问派生类中的受保护成员

Posted

技术标签:

【中文标题】访问派生类中的受保护成员【英文标题】:Accessing protected members in a derived class 【发布时间】:2011-03-15 22:18:50 【问题描述】:

我昨天遇到了一个错误,虽然很容易解决,但我想确保我对 C++ 的理解是正确的。

我有一个带有受保护成员的基类:

class Base

  protected:
    int b;
  public:
    void DoSomething(const Base& that)
    
      b+=that.b;
    
;

这编译和工作得很好。现在我扩展 Base 但仍想使用 b:

class Derived : public Base

  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    
      b+=that.b;
      d=0;
    
;

请注意,在这种情况下,DoSomething 仍然引用 Base,而不是 Derived。我希望我仍然可以访问Derived 内部的that.b,但我收到cannot access protected member 错误(MSVC 8.0 - 尚未尝试 gcc)。

显然,在b 上添加一个公共吸气剂解决了这个问题,但我想知道为什么我不能直接访问b。我认为,当您使用公共继承时,受保护的变量仍然对派生类可见。

【问题讨论】:

查看gotw.ca/gotw/076.htm(注意:不要在生产代码中使用这些东西)。 【参考方案1】:

类只能访问此类或派生类实例的受保护成员。它不能访问父类或表亲类实例的受保护成员。

在您的情况下,Derived 类只能访问 Derived 实例的 b 受保护成员,而不是 Base 实例的受保护成员。

将构造函数更改为采用Derived 实例将解决问题。

【讨论】:

@AnishaKaul:您只能在您的类型的实例中访问基类的受保护成员,而不是表亲类型。例如,Button 无法从 Control 访问 TextBox 上的受保护属性。 You can only access your base class' protected members in an instance of your type, not a cousin type 你又写了和上面写的一样的声明。请看这里:***.com/questions/9139824/… @SLaks “更改构造函数以采用 Derived 实例也将解决问题”是什么意思。 ? @SLaks 但是为什么 Base 类的实例可以访问该 Base 类的其他实例的 pivate 成员? 基类中的访问器方法,虚拟的和受保护的,您可以从派生类调用,传递对基类或派生类的另一个实例的引用?【参考方案2】:

protected成员可以访问:

通过this指针 或相同类型的受保护成员,即使在基中声明 或来自朋友类、函数

要解决您的问题,您可以使用最后两个选项之一。

在 Derived::DoSomething 中接受 Derived 或向 Base 声明 Derived friend

class Derived;

class Base

  friend class Derived;
  protected:
    int b;
  public:
    void DoSomething(const Base& that)
    
      b+=that.b;
    
;

class Derived : public Base

  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    
      b+=that.b;
      d=0;
    
;

在某些情况下,您也可以考虑使用公共 getter。

【讨论】:

【参考方案3】:

如前所述,这就是语言的工作方式。

另一种解决方案是利用继承并传递给父方法:

class Derived : public Base

  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    
      Base::DoSomething(that);
      d=0;
    
;

【讨论】:

我在问题中举了一个不好的例子,但我不能调用 Base::DoSomething,因为当 DoSomething 进入 Derived 而不是 Base 时,它​​实际上是在做不同的事情。【参考方案4】:

您可以访问Derived 的受保护成员,但不能访问Base 的受保护成员(即使它是Derived 的受保护成员的唯一原因是因为它继承自Base

【讨论】:

这不起作用。考虑“您可以访问Derivedprivate 成员。”以及对继承的private 成员Base 的影响。【参考方案5】:

您可以尝试使用 static_cast(pBase)->Base::protected_member ...

class Base

  protected:
    int b;

  public:
    ...
;

class Derived : public Base

  protected:
    int d;

  public:
    void DoSomething(const Base& that)
    
      b += static_cast<const Derived*>(&that)->Base::b;
      d=0;
    
    void DoSomething(const Base* that)
    
      b += static_cast<const Derived*>(that)->Base::b;
      d=0;
    
;

【讨论】:

如果that的动态类型不是(cv)Derived,the behavior is undefined。 但是,对于这种情况,b 始终是基类的数据成员! 或者更好,你可以使用:b += static_cast(that)->Base::b;【参考方案6】:
class Derived : public Base

  protected:
    int d;
  public:
    void DoSomething()
    
      b+=this->b;
      d=0;
    
;

//this will work

【讨论】:

【参考方案7】:

在hack for stl之后,我写了一个小代码,似乎解决了访问派生类中受保护成员的问题

#include <iostream>

class B

protected:
    int a;
public:
    void dosmth()
    
        a = 4;
    

    void print() std::cout<<"a="<<a<<std::endl;
;

class D: private B

public:
    void dosmth(B &b)
    
        b.*&D::a = 5;
    
;

int main(int argc, const char * argv[]) 

    B b;
    D d;
    b.dosmth();
    b.print();
    d.dosmth(b);
    b.print();

    return 0;


打印

a=4
a=5

【讨论】:

事实证明,我的示例与上面发布的示例几乎相同。我也徘徊它的工作原理。从我的观点来看,它转换为派生类型,但我不确定。【参考方案8】:

使用this指针访问受保护的成员

class Derived : public Base

  protected:
    int d;
  public:
    void DoSomething(const Base& that)
    
      this->b+=that.b;
      d=0;
    
;

【讨论】:

这个答案是错误的。派生类无法访问基类的“b”,因为它被声明为受保护(这是用户首先要求的)。此代码将生成编译器错误。 什么没有回答。问题出在thatb 上。添加this-&gt; 不仅不相关,而且完全没有操作,因为如果省略它是隐含的。我希望人们对一门语言有一点了解,并在将其作为答案发布之前测试他们编写的任何代码。 这行得通(至少在visual studio 2019中),我不知道为什么它被否决了。

以上是关于访问派生类中的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章

C#访问派生类中的受保护成员[重复]

从派生类访问基类中的受保护成员

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]

在派生类中无法访问受保护的成员

无法访问派生类中的受保护方法

在派生类中使用来自虚拟基类的受保护 ctor