C++ 关于受保护成员函数和派生类访问的混淆
我与一位同事讨论了为什么以下内容不能在Visual Studio 2008中编译:C++ 关于受保护成员函数和派生类访问的混淆,c++,visual-studio,inheritance,C++,Visual Studio,Inheritance,我与一位同事讨论了为什么以下内容不能在Visual Studio 2008中编译: class base { protected: virtual void f(){} }; class a : public base { public: void fa(base* pb) { pb->f(); // error C2248: 'base::f' : cannot access protected member declared in class
class base
{
protected:
virtual void f(){}
};
class a : public base
{
public:
void fa(base* pb)
{
pb->f(); // error C2248: 'base::f' : cannot access protected member declared in class 'base'
}
};
他认为这是完全合理的,但我认为这是一个奇怪的限制,如果我想要base
及其所有派生类成为一个封闭系统,我仍然需要将base
的一些成员公开,以便他们都可以通过公开派生的共享接口相互交谈
是否有一些我没有想到的用例,允许访问这些受保护的成员可能会破坏受保护成员的性质?如果编译器允许这样的事情,那么您可以很容易地破坏封装。想想这个:
base b;
a foo;
foo.fa(b); // we can now easily access/modify protected elements of `b`
在这种情况下,派生对象foo
和基b
之间没有关系,但是您可以使用派生对象访问其“内脏”。这应该是不可能的(至少是imho)
只需在a.fa()
内部执行f()
就可以了,因为您只需修改a
的基本部分,而不是一些不相关的对象
更具体地说,您可以编写一个“包装器”,它将对任何类禁用protected
:
#include <iostream>
class Base
{
public: // protected in your case, public here so it compiles
int x{42};
public:
int getx() {return x;}
};
template<typename T> // wrapper
class DisableProtected: public T
{
public:
void modify(Base* b)
{
b->x = 24;
}
};
int main()
{
Base base;
std::cout << base.getx() << std::endl;
DisableProtected<Base> foo;
foo.modify(&base); // can modify any Base
std::cout << base.getx() << std::endl;
}
#包括
阶级基础
{
public://在您的情况下受保护,此处为public,因此它可以编译
int x{42};
公众:
int getx(){return x;}
};
模板//包装器
类DisableProtected:public T
{
公众:
无效修改(基本*b)
{
b->x=24;
}
};
int main()
{
基地;
std::cout接近重复项:
是否有一些我没有想到的用例,允许访问这些受保护的成员会破坏受保护成员的性质
我相信这是为了防止一个派生类与兄弟派生类的不变量相混淆
class A {
protected: void foo();
};
class B : public A {
// complicated code
};
class C : public A {
void bar(B* b) {
b->foo();
}
};
这有效地允许C
只修改B
的A
子对象,这可能会违反B
对其A
子对象施加的不变量,而C
是不可能知道的。有趣的故事。我刚刚从比亚恩那里得到了关于这个主题的回复。这是他的回复
考虑
class B : public base
{
public:
// ...
};
A a;
B b;
a.f(&b); // a manipulated b's base
这导致了一些微妙的错误。这是有效的:
class A : public base
{
public:
void fa(base* pb)
{
f(); // use your own base
}
};
我不确定这是否是一件可怕的事情。在我看来,强迫我公开那些不应该公开的成员肯定没有那么邪恶。@cppgy我同意,但总体而言,通过我提到的方案,使用你的方案基本上使受到保护
与公开
相同。这可能是Stroustrup不允许的原因否则,任何人都可以使用指向Base
的指针编写一个包装器,然后通过包装器访问任何Base
对象的受保护成员。邪恶?不是真的,但是protected
失去了它的意义。我不确定我是否相信这个参数。你不是自己在修改b
的元素,你是在这样做g通过一种逻辑上应该能够修改这些元素的方法来访问它。与private
的保护相比,您可以毫无问题地访问另一个对象的私有元素。@vsoftco这就是受保护和私有的区别。受保护是一种更允许的数据隐藏,允许一些访问在某些情况下。在我看来,如果你想阻止你所描述的问题,private就足够了。@不是你的示例,而是一个不涉及派生类的类似示例。类方法可以访问自己的私有成员,也可以访问该类的另一个对象的私有成员(通过指针或引用)例如,你应该让他在这里贴一个答案:))