试图在 C++ 中调用子 class 中父 class 的受保护函数

trying to call protected function of parent class in child class in c++

我一直以为我懂继承,但显然我不懂。我想从子 class 调用同一父 class 的另一个实例的受保护成员函数,如以下示例代码所示:

#include <iostream>

class Parent {
protected:
  void doStuff(){
    std::cout << 5 << std::endl;
  }
};

class Child : public Parent {
public:
  void pubfunc(Parent* p){
    p->doStuff();
  }
};

int main(){
  Child* c = new Child();
  Parent* p = new Parent();
  c->pubfunc(p);
  return 0;
}

但是,此代码的编译失败并显示:

In member function ‘void Child::pubfunc(Parent*)’:
error: ‘void Parent::doStuff()’ is protected
error: within this context

我不想让 Child class 成为 Parent class 的 friend 以避免前向声明和前向包含子项class尽可能多。另外,我不想做 doStuff public,因为在错误的情况下使用它真的会弄乱 Parent 的内部结构。

为什么会出现这个错误,最优雅的解决方法是什么?

class Parent 
{
protected:
    virtual void doStuff()
    {
        std::cout << 5 << std::endl;
    }
};

class Child : public Parent 
{
protected:  
    void doStuff() override
    {
        std::cout << 8 << std::endl;
    }

public:

    void pubfunc(Parent* p)
    {
        ((Child*)p)->doStuff();
    }
};

int main()
{
    Child* c = new Child();
    Parent* p = new Parent();
    c->pubfunc(p);      // will print 5
    c->pubfunc(c);      // will print 8
    return 0;
}

受保护的成员可以在定义它们的 class 和从 class 继承的 class 中访问。有时,当人们看到这种错误时,它会让人感到困惑。但实际上你为父对象调用了 doStuff 函数,如果函数调用在继承 class 内完成,它不会计量。如果您从 main() 调用 doStuff 函数,结果将是相同的。

主要问题在于,如果 C++ 允许您直接访问基 class 指针所指对象的非 public 成员,那么您可以轻松访问简单地通过从公共基础派生对象。

这仍然是 C++ 类型系统中的一个已知 漏洞 ,如下所示,您无需修改​​基 class 即可获得该访问权限,并且无需使用强制转换或类似的东西。

在第三个抓手上,你应该做的是直接在基class中支持预期的用法,通过在那里添加一个static成员函数,如下:

#include <iostream>
using namespace std;

class Base
{
protected:
    void doStuff()
    {
        cout << 5 << endl;
    }

    static void doStuff( Base* p ) { p->doStuff(); }
};

class Derived : public Base
{
public:
    void pubfunc( Base* p )
    {
        doStuff( p );
    }
};

auto main() -> int
{
    Derived d;
    Base b;
    d.pubfunc( &b );
}

以我的愚见,这是最清晰和优雅的。

但为了完整性,类型系统漏洞:

#include <iostream>
using namespace std;

class Base
{
protected:
    void doStuff()
    {
        cout << 5 << endl;
    }
};

class Derived : public Base
{
public:
    void pubfunc( Base* p )
    {
        (p->*&Derived::doStuff)();
    }
};

auto main() -> int
{
    Derived d;
    Base b;
    d.pubfunc( &b );
}

不过我推荐 static 成员函数。