为什么允许通过基类的指针调用派生类的私有虚方法?

Mih*_*yan 13 c++ virtual inheritance access-specifier

# include <iostream>
using namespace std;

class A
{
    public:
    virtual void f()
    {
        cout << "A::f()" << endl;
    }
};
class B:public A
{
    private:
    virtual void f()
    {
        cout << "B::f()" << endl;
    }
};
int main()
{
    A *ptr = new B;
    ptr->f();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码正常工作并打印B :: f().我知道它是如何工作的,但为什么允许这个代码呢?

Ste*_*sop 14

访问控制在编译时执行,而不是在运行时执行.通常无法调用f()知道指向的对象的运行时类型ptr,因此不会检查派生类的访问说明符.这就是允许通话的原因.

至于为什么B级被允许使用私有功能覆盖 - 我不确定.当然B违反了它从A继承所暗示的接口,但一般来说C++语言并不总是强制继承接口,所以它的Just Plain Wrong并不意味着C++会阻止你.

所以我猜这个类B可能有一些用例 - 替换仍然适用于动态多态,但静态B不能替代A(例如,可以有调用的模板f,可以使用A作为参数但不能以B为参数).可能存在这种情况,这正是您想要的.当然,这可能只是其他一些考虑因素的意外后果.

  • @MSalters:C++ 中有两种不同类型的替换,因为 C++ 中有(至少)两种不同类型的多态性。我们可以分别评估 LSP 是否适用于每个。例如,如果您的 B 对象在函数调用中按值传递,该函数调用使用模板参数推导从模板实例化函数,那么它很可能不会被切片,并且确实可以将 `f` 访问为 `B::f`。B 不满足 A 满足的所有概念,基本上,所以对象只有在类型被剥离后才可替换(例如使用 A*,或转换为 A)。 (2认同)