什么时候应该限制派生类中虚拟函数的可访问性?

Jon*_*Jon 5 c++ virtual-functions access-specifier code-design

请考虑以下代码:

class Base
{
public:
    virtual void Foo() {}
};

class Derived : public Base
{
private:
    void Foo() {}
};

void func()
{
    Base* a = new Derived;
    a->Foo(); //fine, calls Derived::Foo()

    Derived* b = new Derived;
//  b->Foo(); //error
    static_cast<Base*>(b)->Foo(); //fine, calls Derived::Foo()
}
Run Code Online (Sandbox Code Playgroud)

关于此事,我听过两种不同的思想流派:

1)保持可访问性与基类相同,因为用户无论如何都可以使用static_cast来获取访问权限.

2)使功能尽可能私密.如果用户需要a-> Foo()而不是b-> Foo(),那么Derived :: Foo应该是私有的.如果需要,它总是可以公开.

是否有理由偏好其中一个?

Jon*_*oni 6

限制对子类型中成员的访问会破坏Liskov替换原则(SOLID中的L ).总的来说,我会反对它.

更新:它可能"工作",因为代码编译并运行并产生预期的输出,但如果你隐藏了一个成员,你的意图可能是使子类型不如原始子类型.这就是打破原则的原因.相反,如果您打算通过仅留下API用户感兴趣的内容来清理子类型接​​口,请继续执行.

  • 我不认为这打破了替代原则.在任何需要引用"Base"的地方,你仍然可以使用对"Derived"的引用,它会正常工作. (2认同)
  • @Jon:这在很大程度上取决于你如何打包和分发你的代码.如果有些客户打电话给你说"需要刚刚出现",那么你能否以足够快的速度将新版本推出门外?至少在理论上,将成员函数从`private`更改为`public`可能会破坏二进制兼容性,尽管我怀疑在实践中你几乎可以使用任何可执行格式.鉴于有一个解决方法,我认为最好是支持它或不支持它,不要认为它可用,即使它不可用,因为你可以在以后添加它. (2认同)