关于受保护的成员函数和派生类访问的混淆

Confusion regarding protected member functions and derived class access

本文关键字:访问 派生 函数 受保护 成员      更新时间:2023-10-16

我与一位同事讨论了为什么以下内容不能在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的一些成员公开,这样他们就可以通过共享接口相互交谈,他们都是公开派生的。

有没有一些用例我没有想到,允许访问这些受保护的成员可能会破坏受保护成员的性质?

如果编译器允许这样做,那么您可以很容易地破坏封装。想想看:

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;
}

近重复:

  • 受保护字段的细微C++继承错误
  • 我可以从派生类中的静态函数访问受基类保护的成员吗
  • 父类中受保护的数据在子类中不可用
  • 访问父';s受保护的变量

有没有一些用例我没有想到,允许访问这些受保护的成员可能会破坏受保护成员的性质?

我认为这是为了防止一个派生类扰乱兄弟派生类的不变量。考虑

class A {
    protected: void foo();
};
class B : public A {
    // complicated code
};
class C : public A {
    void bar(B* b) {
        b->foo();
    }
};

这有效地允许C只修改BA子对象,这可能违反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
    }
};