为什么 C++ 允许私有父类的指针多态性?

Why does C++ allow this pointer polymorphism of private parent?

如果我从一个基 class 中私下继承一个派生的 class,我就无法获得 inhritetted class 的多态性。

但是我可以在派生的class中得到'this'指针的多态性。

我很好奇为什么 'this' 指针允许多态到其私有父级,但是 class 之外的指针却不允许。

提前致谢!

#include <iostream>

class Shape
{
public:
    virtual void say() const = 0;
    virtual void who()
    {
        std::cout << "Shape" << std::endl;
    }
    void whoAmI() {
        this->who();
    }
};

class Squire : private Shape
{
public:
    virtual void say() const
    {
        std::cout << "Squire" << std::endl;
    }
    
    void doSay()
    {
        // why this pointer to Shape type is allowed in class?
        privateSay(this);
    }
    
private:
    void privateSay(Shape* s)
    {
        s->say();
    }
};

void say(Shape* s)
{
    s->say();
}

int main(int argc, const char * argv[]) {
    // insert code here...
    
    Squire* s = new Squire();
    // allowed
    s->doSay();
    
    // not allowd, compile errors
    // Cannot cast 'Squire' to its private base class 'Shape'
    say(s);
    
    return 0;
}

=========

编辑澄清。 感谢所有的答案。 为了澄清我的问题,我认为如果 C++ 允许这种行为,它可能会稍微违反 encapsulation

更清晰的案例:

#include <iostream>

class Base
{
public:
    void baseFunc() const
    {
        std::cout << "baseFunc" << std::endl;
    }
};

class Worker
{
public:
    Worker(Base *pBase)
    {
        base_ = pBase;
    }
    
    void breakFunc() const
    {
        base_->baseFunc();
    }
private:
    Base *base_;
};

class Derived : private Base
{
public:
    void init()
    {
        worker_ = new Worker(this);
    }
    
    Worker* getWorker()
    {
        return worker_;
    }

private:
    Worker *worker_;
};

int main()
{
    Derived derived;
    derived.init();
    
    
    Worker *worker = derived.getWorker();
    worker->breakFunc();
}

Baseclass的对象只作为父对象部分存在于Derivedclass的对象中,但是Derivedclass继承Baseclassprivately,意思是Derived的对象classhas-an Base的对象class,私下.

上面的代码违反了Derivedclass的封装规则,但是在编译过程中甚至没有给出警告。

在我看来,这种情况下应该使用显式强制转换,或者在编译时给出警告。

私有继承意味着来自基础 class 的 publicprotected 符号成为派生 class 的 private 符号。 private 基础 class 的符号无法被派生 class 访问。仍然可以覆盖的私有虚拟方法除外。

this 指针,或者一般的 Class* ptr 在 class 内部使用,可以访问 class.

的私有字段

由于符号 Shape::sayShape 中是 public,它在 Squire 中变为私有(顺便说一句,你是说 Square 吗?)。这会阻止 public 使用它,但不会被 this 使用。由于虚拟规则,这将“私有化”整个重写方法链。

void Squire::privateSay(Shape* s)
{
    // Works because `Shape::say` is a public symbol of Shape -> private symbol of Squire and `this` can access private symbols.
    s->say();
}
void say(Shape* s)
{
    // Shape::say is a private symbol, obviously cannot be called.
    s->say();
}

如果存在私有 Shape::foo() 方法,即使在 Squire 的任何方法中通过 this 也无法访问它。

这里问的问题是为什么基class在私有继承时可以访问
答案很简单:因为基础 classes 总是对继承可见,无论继承类型如何

当碱基在上下文中可见时,您可以 static_cast 到碱基 class。


class base
{
};

class inherited : base
{
public:

void foo()
{
    // works, base is visible within the method.
    auto pBase = static_cast<base*>(this);
}
};

int main() {
    inherited i{};
    // auto pBase = static_cast<base*>(&i); // won't compile, base is not visible
    return 0;
}