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

时间:2011-01-06 20:59:05

标签: c++ inheritance private protected

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

7 个答案:

答案 0 :(得分: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
} 

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

答案 1 :(得分:7)

一般情况下,您会在文献(以及此处的其他答案)中找到protected / private继承意味着该类不能用作base。事实(其他一些答案提示)是只有继承的可见性受操作的影响。 derived一个base类,即使外部代码不能看到它。

任何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"
}

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

答案 2 :(得分:6)

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

这可能不足以回答问题的意图。如果你不能将结果对象用作基类的实例,你可能会问“以及为什么拥有私有和受保护的继承?”

嗯,非公共继承意味着促进“在两个类之间的关系中实现”(而公共继承促进了“is-a”关系)。换句话说,您打算重用部分或全部基类功能,以便为您自己的消费者提供服务。

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

请查看this,了解更长时间的内容。

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

答案 3 :(得分:5)

简而言之,因为私有继承是实现的继承,而不是 interface 的继承。私有子类Derived对象不是 Base,但是以 Base实现的。 Base的公共受保护成员和Derived受保护成员可见{{1}},但他们变为私有,因此外部世界无法访问。因此,私有继承可以被认为是组合的一种特殊形式,实际上很少需要它。 (而且受保护的继承实际上从来没有 - 实际上甚至Bjarne Stroustrup也不知道保护继承的含义。)

答案 4 :(得分:5)

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

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

Class B is a version of class A.

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

class A {};
class B : private A {};

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

class A {};
class B
{
private:
    A a;
};

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

答案 5 :(得分:3)

您可以将公共/受保护/私有继承视为任何类成员的可访问性:它取决于“您想要显示多少”。

私有(或受保护,略有不同的方式)继承是一种未向外界展示的关系。因此,您不能将派生类型的对象视为其私有基础,因为您无法“看到”此关系甚至存在。

答案 6 :(得分:3)

  

为什么子类的对象不能   被视为的对象   超类,当继承是   受保护还是私人?

它当然可以被视为超级类的一个对象。但是,这种考虑受到限制(通过公共/受保护/私人入侵修饰符),但仅限于本身(私有继承)或它的子类(受保护的继承)。

不允许所有外部对象都被视为类,类似于不允许访问受保护或私有方法或变量的方式。如果表达得当,这种类比是相当合适的。

因此,类本身及其子类(和朋友)可以将其视为is-a关系,但外部世界不允许这样做。

以下代码显示了这一点:

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

class PublicDerived: public Base
{ };

class ProtectedDerived: protected Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class ProtectedSubClass: public ProtectedDerived {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateDerived: private Base {
    void test() {
        Base* base2 = this; // OK
    }
};

class PrivateSubClass: public PrivateDerived {
    void test() {
        Base* base2 = this; // Error (line 28)
    }
};

int main()
{
    PublicDerived   publicD;
    ProtectedDerived protectedD;
    PrivateDerived  privateD;

    Base* base1 = &publicD;
    Base* base2 = &protectedD; // Error (line 39)
    Base* base3 = &privateD; // Error (line 40)
} 

请注意,xxxSubClass类如何从其超类派生出来并不重要。 所有关于超类如何从Base 派生的,这应该是它。

编译器适当地抱怨:

inherit.cpp(28) : error C2247: 'Base' not accessible because 'PrivateDerived' uses 'private' to inherit from 'Base'
        inherit.cpp(1) : see declaration of 'Base'
        inherit.cpp(20) : see declaration of 'PrivateDerived'
        inherit.cpp(1) : see declaration of 'Base'
inherit.cpp(29) : error C2243: 'type cast' : conversion from 'PrivateSubClass *const ' to 'Base *' exists, but is inaccessible
inherit.cpp(39) : error C2243: 'type cast' : conversion from 'ProtectedDerived *' to 'Base *' exists, but is inaccessible
inherit.cpp(40) : error C2243: 'type cast' : conversion from 'PrivateDerived *' to 'Base *' exists, but is inaccessible