Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

C++知识点整理——继承

$
0
0

         继承的基础知识在这就不进行介绍了,“知识点整理”是平时对不是经常用到的相关知识点的一个整理,注意一些不太常见,但是很有意思的知识,有助于加深我们对C++的认识。

一:私有继承

         私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。

         这里将私有继承,因为前段时间遇见一个题目:在private inheritance(私有继承)与composition(复合)之间,你该做如何选择?当时很困惑,因为很少(几乎看不到)有用到私有继承。这让我认真思考了翻。

         C++将publicinheritance(公有继承)视为一个is-a关系,而私有继承是is-implemented-in-terms-of(是根据……实现的),composition(复合)具有这两种关系。比如D公有继承自B,实际上就是说:每个类型为D的对象也是一个类型为B的对象,但是反之则不然。Student 公有继承自Person,则说一个student是一个person,而不能说一个person是一个student。

在 C++ 领域中,任何期望引数类型为 Person(或 pointer-to-Person 或 reference-to-Person)的函数都可以接受一个 Student object(或 pointer-to-Student 或 reference-to-Student)这一点只对公有继承才成立。

void eat(const Person& p); // anyone can eat
void study(const Student& s); // only studentsstudy
Person p; // p is a Person
Student s; // s is a Student
eat(p); // fine, p is a Person
eat(s); // fine, s is a Student,
// and a Student is-a Person
study(s); // fine
study(p); // error! p isn’t a Student

而私有继承则意味着完全不同的事情。保护继承则意味着什么则是我困惑。如果是私有继承,编译器是不会将派生类对象转型为基类对象。因此私有继承意味着只有implementation实现应该被继承,interface(接口)应该被忽略。

可能更愿意用 public inheritance(公有继承)加 composition(复合)而不用 private inheritance(私有继承)的两个原因:

禁止重定义虚函数,即使是私有继承,虽然不能访问虚函数,但却能重定义。

你可能最小化compilation dependencies (编译依赖),私有继承仍需包含基类头文件,如果composition(复合)可以采用指针作为类变量。

我早些时候谈及 private inheritance(私有继承)主要用武之地是当一个将要成为 derived class(派生类)的类需要访问将要成为 base class(基类)的类的 protected parts(保护构件),或者希望重定义一个或多个它的 virtual functions(虚拟函数),但是 classes(类)之间的概念上的关系却是 is-implemented-in-terms-of,而不是 is-a。然而,我也说过有一种涉及space optimization(空间最优化)的极端情况可能会使你倾向于 private inheritance(私有继承),而不是 composition(复合)。这个极端情况确实非常尖锐:它仅仅适用于你处理一个其中没有数据的 class(类)的时候。这样的 classes(类)没有 non-static data members(非静态数据成员);没有 virtualfunctions(虚函数)(因为存在这样的函数会在每一个 object(对象)中增加一个 vptr。也没有 virtual base classes(虚拟基类)(因为这样的 base classes(基类)也会引起 size overhead(大小成本))。这样的类(空类)理论上是不占用空间,而C++对空类实际上是占用空间的(一个char的大小)。这样你就想到了私有继承一个用武之地——空基优化。但要注意空基优化只对single inheritance(单继承)才可行。

         尽管如此,我们还是要回归基础。大多数 classes(类)不是空的,所以 EBO 很少会成为 private inheritance(私有继承)的一个合理的理由。此外,大多数 inheritance(继承)相当于 is-a,而这正是 public inheritance(公有继承)而非 private(私有)所做的事。composition(复合)和 private inheritance(私有继承)两者都意味着 is-implemented-in-terms-of(是根据……实现的),但是composition(复合)更易于理解,所以你应该尽你所能使用它

         privateinheritance(私有继承)更可能在以下情况中成为一种设计策略,当你要处理的两个 classes(类)不具有 is-a(是一个)的关系,而且其中的一个还需要访问另一个的 protected members(保护成员)或需要重定义一个或更多个它的 virtual functions(虚拟函数)。甚至在这种情况下,我们也看到 public inheritance 和 containment 的混合使用通常也能产生你想要的行为,虽然有更大的设计复杂度。谨慎使用 private inheritance(私有继承)意味着在使用它的时候,已经考虑过所有的可选方案,只有它才是你的软件中明确表示两个 classes(类)之间关系的最佳方法。与 composition(复合)不同,private inheritance(私有继承)能使 empty base optimization(空基优化)有效。这对于致力于最小化object sizes(对象大小)的库开发者来说可能是很重要的。

二:多继承

         多继承的首要问题在于歧义性:两个(或多个)基类有相同的成员,派生类访问该成员时出现歧义。先说下C++解析overloaded functions(重载函数)调用规则:在看到一个函数的是否可访问之前,C++ 首先确定与调用匹配最好的那个函数。只有在确定了 best-matchfunction(最佳匹配函数)之后,才检查可访问性。这就出现多继承下可能永远不会检查某个基类的成员(该成员在两个基类中匹配程度相同,只会检查一个)。因此为了消除歧义,你必须指定哪一个baseclass(基类)的函数被调用:object.baseclass::function。

         而且多继承也易出现菱形继承,这应该很好理解。另外一个解决多继承问题的是采用虚继承。下面就来讲解虚拟继承。

三:虚继承

         虚拟继承:又称作共享继承,这种共享其实也是编译期间实现的。虚拟继承下,只有一个共享的基类子对象被继承,而无论该基类在派生层次中出现多少次。

         使用虚继承的类创建的对象通常比不使用虚继承的要大。访问虚继承中的数据成员也要比那些非虚继承中的要慢。要记住虚继承是要付出成本的。

         我对于 virtual base classes(虚拟基类)(也就是 virtualinheritance(虚拟继承))的建议很简单。首先,除非必需,否则不要使用virtual bases(虚拟基)。缺省情况下,使用non-virtual inheritance(非虚拟继承)。第二,如果你必须使用virtual base classes(虚拟基类),试着避免在其中放置数据。这样你就不必在意它的initialization(初始化)(以及它的turns out(清空),assignment(赋值))规则中的一些怪癖。值得一提的是 Java 和 .NET 中的Interfaces(接口)不允许包含任何数据,它们在很多方面可以和 C++ 中的 virtual base classes(虚拟基类)相比照。

作者:backo880607 发表于2013-3-20 23:47:21 原文链接
阅读:68 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>