我正在与同事讨论为什么以下内容无法在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 'base'
}
};
他认为这是完全合理的,但我认为这是一个奇怪的限制,如果我希望base
及其所有派生类都是一个封闭的系统,我仍然需要制作一些base
公众成员公开,所以他们都可以通过共享界面相互交谈,这些共享界面都是公开传播的。
是否有一些用例我没想到允许访问这些受保护成员的位置会破坏受保护成员的性质?
答案 0 :(得分:2)
如果编译器允许这样的事情,那么你可以轻松破解封装。想一想:
base b;
a foo;
foo.fa(b); // we can now easily access/modify protected elements of `b`
在这种情况下,派生对象foo
和基础b
之间没有关系,但是您可以使用派生来访问其“胆量”。这是不可能的(至少是imho)。
只需在f()
内执行a.fa()
即可,因为您只需修改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;
}
答案 1 :(得分:2)
近重复:
是否有一些用例我没想到允许访问这些受保护成员的位置会破坏受保护成员的性质?
我认为这是为了防止一个派生类弄乱兄弟派生类的不变量。考虑
class A {
protected: void foo();
};
class B : public A {
// complicated code
};
class C : public A {
void bar(B* b) {
b->foo();
}
};
这有效地允许C
仅修改A
的{{1}}子对象,这可能违反B
对其B
子对象强加的不变量,A
子对象{ {1}}不能指望知道。
答案 2 :(得分:0)
有趣的故事。我刚收到Bjarne对此主题的回复。这是他的回应。
考虑
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
}
};