第14章 C++中的代码重用

1. 使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现)。获得接口是is-a关系的组成部分。而使用组合,类可以获得实现,但不能获得接口。不继承接口是has-a关系的组成部分。

2. C++还有另一种实现has-a关系的途径——私有继承。使用私有继承,基类的公有成员和保护成员都将称为派生类的私有成员。这意味着基类方法将不会称为派生类对象公有接口的一部分,但可以在派生类的成员函数中使用它们。

3. 包含将对象作为一个命名的成员对象添加到类中,而私有继承将对象作为一个未命名的继承对象添加到类中。我们将使用术语子对象(subobject)来表示通过继承或包含添加的对象。

因此,私有继承提供的特性和包含相同:获得实现,但不获得接口。所以,私有继承也可以用来实现has-a关系。

4. 要进行私有继承,请使用关键字private来定义类。实际上,private是默认值,因此省略访问限定符也将导致私有继承。

5. 使用包含还是继承来建立has-a关系

大多数C++程序员倾向于包含。首先,它易于理解。类声明中包含表示被包含类的显示命名对象,代码可以通过名称引用这些对象,而使用继承将使关系更抽象。其次,继承会引起很多问题,尤其从多个基类继承时,可能必须处理很多问题,如包含同名方法的独立的基类或共享祖先的独立基类。总之,使用包含不太可能遇到这样的麻烦。另外,包含能够包括多个同类的子对象。如果某个类需要3个string对象,可以使用包含声明3个独立的string成员。而继承只能使用一个这样的对象(当对象都没有名称时,将难以区分)。

6. 通常,应使用包含来建立has-a关系;如果新类需要访问原有类的保护成员,或需要重新定义虚函数,则应使用私有继承。

7. 使用保护继承时,基类的公有成员和保护成员都将称为派生类的保护成员。和私有继承一样,基类的接口在派生类中也是可用的,但在继承层次结构之外是不可用的。当从派生类派生出另一个类时,私有继承和保护继承的主要区别便呈现出来了。使用私有继承时,第三代类将不能使用基类的接口,是因为基类的公有方法在派生类中将变成私有方法;使用保护继承时,基类的公有方法和保护方法在第二代类中将变成保护的,因此第三代类可以使用它们。保护继承和私有继承一样,都是表示has-a关系。

8. 隐式向上转换意味着无需进行显式类型转换,就可以将基类指针或引用指向派生类对象。

公有继承能隐式向上转换,保护继承只能在派生类中才能隐式类型转换,私有继承不能隐式类型转换。

9. 使用using重新定义访问权限

使用保护派生或私有派生时,基类的公有成员将称为保护成员或私有成员。假如要让基类的方法在派生类外面可用,方法之一是定义一个使用该基类方法的派生类方法。另一种方法是使用using声明,来指出派生类可以使用的特定基类成员,即使采用的是私有派生(注意:using声明只使用函数名,没有圆括号、函数特征标和返回类型)。P550

10. 多重继承MI可能会给程序员带来很多问题。其中两个主要的问题是:从两个不同的基类继承同名方法;从两个或更多相关基类那里继承同一个类的多个实例。

11. 虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。例如:通过在类声明中使用virtual,可以使Worker被用作Singer和Waiter的虚基类(virtual和public的次序无关紧要):

class Singer : virtual public Worker{…}

class Waiter : public virtual Worker{…}

然后,可以将SingingWaiter类定义为:

class SingingWaiter : public Singer, public Waiter{…}

12. P557-P558虚基类新的构造函数规则

C++在基类是虚的时,为避免信息传递冲突,禁止信息通过中间类自动传递给基类。然而,编译器必须在构造派生对象之前构造基类对象组件。如果没有显示指出构造函数,编译器将调用虚基类的默认构造函数。如果不希望通过默认构造函数来构造虚基类对象,则需要显式地调用所需的基类构造函数。

13. P558哪个方法

多重继承可能导致函数调用的二义性。可以使用作用域解析运算符来澄清编程者的意图。

SingingWaiter newhire(“Elise Hawks”, 2005, 6, soprano);

newhire.Singer::Show();

然而,更好的方法是在SingingWaiter中重新定义Show(),并指出要使用哪个Show()。

14. 混合使用虚基类和非虚基类

当类通过多条虚途径和非虚途径继承某个特定的基类时,该类将包含一个表示所有的虚途径的基类子对象和分别表示各条非虚途径的多个基类子对象。

15. 模板类以template <class Type>(或template <typename Type>)打头,如果在类声明外定义类方法,每个函数头还需加上模板前缀template <class Type>和类限定符(Stack<Type>::)。

16. 知道模板类不是类和成员函数定义至关重要。它们是C++编译器指令,说明了如何生成类和成员函数定义。不能将模板成员函数放在独立的实现文件中。由于模板不是函数,它们不能单独编译。为此,最简单的方法是将所有模板信息放在一个单独的头文件中,并在要使用这些模板的文件中包含该头文件。

17. P574-P575,在类声明中,都可以使用Stack;在类外,在模板函数定义内(包括形参)可以使用Stack,指定返回类型或使用作用域解析运算符时,必须使用完整的Stack<Type>。

18. template <class T, int n>中,T为类型参数,n为非类型参数或表达式参数。表达式参数有一些限制。表达式参数可以是整形、枚举、引用或指针。因此,double m是不合法的,double *rm和double *pm是合法的。另外,模版代码不能修改参数的值,也不能使用参数的地址。即不能使用n++或&n等表达式。另外,实例化模板时,用作表达式参数的值必须为常量表达式。

19. P578-P582模板多功能性(将模板类用作基类、组件类、或其他模板的类型参数)、递归使用模板、使用多个类型参数。

20. 模板的具体化

类模板和函数模板很相似,因为可以有隐式实例化、显式实例化和显式具体化,它们统称为具体化。

1)  隐式实例化:

ArrayTP<int, 100> stuff;

编译器在需要对象之前,不会生成类的隐式实例化:

ArrayTP<int, 100> *pt;//不需要对象

pt = new ArrayTP<double, 30>//需要对象

2)  显式实例化

template class ArrayTP<string, 100>;

在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。

3)  显式具体化

显式具体化是特定类型(用于替换模板中的泛型)的定义。

template <> class SortedArray(const char *);

21. P583部分具体化

//通用模板

template <class T1, class T2> class Pair {…};

//具体化T2为int

template <class T1>  Pair<T1, int>{…};

关键字template后面的<>声明的是没有被具体化的类型参数,如果都被具体化,则<>为空,这将导致显式具体化。

22. P584成员模板:在模板类内声明模板类或函数模板

23. P586将模板用作模板参数

24. P588-P593模板类和友元

模板类声明也可以有友元。模板的友元分3类:

非模板友元,友元本身不是模板函数,而只是使用了隐式实例化的模板类作为参数。

约束模板友元,类的每一个具体化都获得匹配的友元,友元的类型取决于具体化的类型。在类声明外面声明友元函数模板。

非约束模板友元,友元的每一具体化都是类的所有具体化的友元。在类声明里面声明友元函数模板。

C++ primer plus读书笔记——第14章 C++中的代码重用的更多相关文章

  1. 《C++ Primer Plus》读书笔记之十二—C++中的代码重用

    第14章 C++中的代码重用 1.C++代码重用方法:公有继承.使用本身是另一个类的对象的类成员(这种方法称为包含.组合或层次化).私有或保护继承.类模板等. 2.模板特性意味着声明对象时,必须指定具 ...

  2. 《C++ Primer Plus》第14章 C++中的代码重用 学习笔记

    C++提供了集中重用代码的手段.第13章介绍的共有继承能够建立is-a关系,这样派生类可以重用基类的代码.私有继承和保护继承也使得能够重用基类的代码,单建立的是has-a关系.使用私有继承时,积累的公 ...

  3. SQL Server2012 T-SQL基础教程--读书笔记(1-4章)

    SQL Server2012 T-SQL基础教程--读书笔记(1-4章) SqlServer T-SQL 示例数据库:点我 Chapter 01 T-SQL 查询和编程背景 1.3 创建表和定义数据的 ...

  4. C primer plus 读书笔记第三章

    本章的标题是数据和C,主要内容是介绍数据类型中的整数类型和浮点数类型. 本章的第一段代码 #include <stdio.h> int main(void) { float weight; ...

  5. C++ primer plus读书笔记——第12章 类和动态内存分配

    第12章 类和动态内存分配 1. 静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域运算符来指出静态成员所属的类.但如果静态成员是整形或枚举型const,则可以在类声明中初始化 ...

  6. C++ primer plus读书笔记——第17章 输入、输出和文件

    第17章 输入.输出和文件 1. 对键盘进行输入缓冲可以让用户在将输入传输给程序之前返回并更正.C++程序通常在用户按下回车键时刷新输入缓冲区. 2. 一些I/O类 streambuf类为缓冲区提供了 ...

  7. C++ primer plus读书笔记——第16章 string类和标准模板库

    第16章 string类和标准模板库 1. string容易被忽略的构造函数: string(size_type n, char c)长度为n,每个字母都为c string(const string ...

  8. C++ primer plus读书笔记——第15章 友元、异常和其他

    第15章 友元.异常和其他 1. 友元类的所有方法都可以访问原有类的私有成员和保护成员.另外,也可以做更严格的限制,只将特定的成员函数指定为另一个类的友元.哪些函数.成员函数.或类为友元是由类定义的, ...

  9. C++ primer plus读书笔记——第13章 类继承

    第13章 类继承 1. 如果购买厂商的C库,除非厂商提供库函数的源代码,否则您将无法根据自己的需求,对函数进行扩展或修改.但如果是类库,只要其提供了类方法的头文件和编译后的代码,仍可以使用库中的类派生 ...

随机推荐

  1. [倍增]luogu P4155 [SCOI2015]国旗计划

    题面 https://www.luogu.com.cn/problem/P4155 问在环上最少取多少个区间能完全覆盖环 分析 首先发现是环,先把端点变为2n方便处理,注意离散化 其次要删去贡献不如其 ...

  2. 未来直播 “神器”,像素级视频分割是如何实现的 | CVPR 冠军技术解读

    被誉为计算机视觉领域 "奥斯卡" 的 CVPR 刚刚落下帷幕,2021 年首届 "新内容 新交互" 全球视频云创新挑战赛正火热进行中,这两场大赛都不约而同地将关 ...

  3. WebGPU[1] 三角形

    代码见: https://github.com/onsummer/my-dev-notes/tree/master/webgpu-Notes/01-triangle 如果本篇的代码不能跑了,请联系我或 ...

  4. 为什么数据库字段要使用NOT NULL?

    最近刚入职新公司,发现数据库设计有点小问题,数据库字段很多没有NOT NULL,对于强迫症晚期患者来说,简直难以忍受,因此有了这篇文章. 基于目前大部分的开发现状来说,我们都会把字段全部设置成NOT ...

  5. 为什么要放弃 JSP?他们终于给出了答案

    前言 以前的项目大多数都是Java程序猿又当爹又当妈,既搞前,又搞后端. 随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只负责前端的事情,后端工程师只管后端的事情.正 ...

  6. Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step

    翻译自 Mohamad Lawand 2021年1月25日的文章 <Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step ...

  7. HashSet、CopyOnWriteArraySet、ConcurrentSkipListSet源码解析(JDK1.8)

    目录 HashSet源码解析 HashSet简单使用的demo HashSet中的变量 HashSet的构造函数 HashSet的add方法 HashSet的iterator方法 HashSet的si ...

  8. JavaScript实现斐波那契数列

    什么是斐波那契数列 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为&qu ...

  9. 简析JAVA8函数式接口

    一,定义 "有且只有一个抽象方法的接口"----函数式接口的定义. @FunctionalInterface public interface Ifun{ void test(); ...

  10. ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息

    ASP微信服务号H5客户登陆,且获取客户授权的用户基本信息是需要客户授权,下面讲解详细步骤: 第一步:客户点击登录页,自动跳转到微信服务器端获取code 第二步:用第一步获取的code去获取客户的ac ...