访问派生类中的受保护成员
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
)
【讨论】:
这不起作用。考虑“您可以访问Derived
的private
成员。”以及对继承的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_castclass 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”,因为它被声明为受保护(这是用户首先要求的)。此代码将生成编译器错误。 什么没有回答。问题出在that
的b
上。添加this->
不仅不相关,而且完全没有操作,因为如果省略它是隐含的。我希望人们对一门语言有一点了解,并在将其作为答案发布之前测试他们编写的任何代码。
这行得通(至少在visual studio 2019中),我不知道为什么它被否决了。以上是关于访问派生类中的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章