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