C++中的公共和私有继承

Nar*_*rek 12 c++ inheritance private protected

正如我们从文献中了解到的公共继承一样,子类(子类)的对象也可以被视为基类(超类)的对象.为什么当继承受到保护或私有时,子类的对象不能被视为超类的对象?

Mar*_*ork 21

因为你看不到它:

class Base
{
    public: virtual ~Base() {}
};

class PublicDerived: public Base
{    };

class PrivateDerived: private Base
{    };

int main()
{
    PublicDerived   publicD;
    PrivateDerived  privateD;

    Base&           base1 = publicD;
    Base&           base2 = privateD; // ERROR
} 
Run Code Online (Sandbox Code Playgroud)

因此,您无法使用可以使用Base对象的PrivateDerived对象.
所以它永远不会像Base类对象那样.


Dav*_*eas 7

一般来说,您会在文献中(以及此处的其他答案)中发现protected/ private继承意味着该类不能用作base.事实(其他一些答案提示)是只有继承的可见性受操作的影响.该derivedbase类,即使外部代码无法看到它.

任何friend或类都可以利用这种关系:

struct base {
   virtual void foo() { std::cout << "base" << std::endl; }
};
void take_base( base& b ) {}
class derived : base // private {
   friend base& to_base( derived& );
   virtual void foo() { std::cout << "derived" << std::endl; }
public:
   base & as_base() { return *this; }
   void call_function() { take_base(*this); } // ok: inside derived, it knows that it is
                                              // in fact a base
};
base& to_base( derived& d ) {
   return d;
}
int main() {
   derived d;
   //d.foo();      // error
   //take_base(d); // error
   take_base( d.as_base() ); // ok, the conversion is performed internally where
                             // access is granted: print "derived"
   take_base( to_base(d) );  // ok, the conversion is performed in a friend function
                             // that has access: print "derived"
}
Run Code Online (Sandbox Code Playgroud)

现在,虽然从技术上来说就是这种情况,但在语义上,当你使用private继承时,你试图建模的不是一个is-a而是一个implemented-in-terms-of关系.这是重要的部分:在阅读代码时,如果你看到private继承,你就不应该考虑is-a而是实现.


Jon*_*Jon 6

在考虑机制如何工作时,"为什么"很简单:因为受保护和私有继承意味着以这种方式工作.

尽管如此,这可能还不足以回答问题的意图.您可能会问" 如果您不能将结果对象用作基类的实例,为什么要有私有和受保护的继承?"

那么,非公共继承意味着促进"在两个类之间的关系中实现"(而公共继承促进了"is-a"关系).换句话说,您打算重用部分或全部基类功能来为您自己的使用者提供服务.

这种情况几乎总是通过聚合而不是继承更好地实现(即,具有"基础"类的成员对象),并且我甚至会说非公共继承是更好的事情.

看看这个是为了更长时间的写作,扩展了上述内容.

更新:作为下面的评论者,有一些(公认的罕见)非公开继承提供了架构功能的机制,否则这是不可能的.阅读它们,因为探索语言的边缘可能非常有启发性.但尝试尽可能少地做到这一点.


Pét*_*rök 5

简而言之,因为私有继承是实现的继承,而不是接口的继承.私有子类Derived对象不是a Base,而是根据实现 Base.公众和受保护的成员Base是可见的Derived,但他们变得私人,因此外部世界无法进入.因此,私有继承可以被看作是一种特殊形式的成分,这实际上是很少需要在实践中.(而且受保护的继承实际上从来没有 - 实际上甚至Bjarne Stroustrup也不知道继承的保护意味着什么.)


Zac*_*and 5

public继承服务于is-a关系的目的.那是:

class A {};
class B : public A {};

Class B is a version of class A.
Run Code Online (Sandbox Code Playgroud)

private继承服务于has-a关系的目的.您可以使用容器模型使用私有继承来编写几乎任何类:

class A {};
class B : private A {};
Run Code Online (Sandbox Code Playgroud)

可以重写(为了清楚起见,通常应该重写):

class A {};
class B
{
private:
    A a;
};
Run Code Online (Sandbox Code Playgroud)

protected继承是类似的private,但实际上几乎不应该使用(Scott Meyers和Herb Sutter都在各自的书中说明了这一点).