前言
个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系。
一直以来都很想深入学习一下C++,将其作为自己的主力开发语言。现在为了完成自己这一直以来的心愿,准备认真学习《C++ Primer Plus》。
为了提高学习效率,在学习的过程中将通过发布学习笔记的方式,持续记录自己学习C++的过程。
一、包含对象成员的类
valarray
类是由头文件
valarray
支持的。这个类用于处理数值(或具有类似特性的类),它支持诸如将数组中所有元素的值相加以及在数组中找出最大和最小的值等操作。
valarray
被定义为一个模板类,以便能够处理不同的数据类型。
使用
valarray
类来声明一个对象时,需要在标识符
valarray
后面加上一对尖括号,并在其中包含所需的数据类型:
valarray<int> q_values;
通常,用于建立
has-a
关系的C++技术是组合(包含),即创建一个包含其他类对象的类。
二、私有继承
私有继承是C++实现
has-a
关系的另一种途径。使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员。这意味着基类方法将不会成为派生对象公有接口的一部分,但可以在派生类的成员函数中使用它们。
要进行私有继承,请使用关键字
private
而不是
public
来定义类(实际上,
private
是默认值,因此省略访问限定符也将导致私有继承)。
Class Student : private std::string, private std:: valarry<double>
{
...
};
使用多个基类的继承被称为多重继承(multiple inheritance,MI)。
通常,应使用包含来建立
has-a
关系;如果新类需要访问原有类的保护成员,或需要重新定义虚函数,则应使用私有继承。
保护继承是私有继承的变体。保护继承在列出基类时使用关键字
protected
:
class Student : protected std:string, protected std::valarry<double>
{
...
};
使用私有继承时,第三代类将不能使用基类的接口,这是因为基类的公有方法在派生类中变成了私有方法;使用保护继承时,基类的公有方法在第二代类中将变成受保护的,因此第三代派生类可以使用它们。
各种继承方式:
特征 | 公有继承 | 保护继承 | 私有继承 |
---|---|---|---|
公有成员变成 | 派生类的公有成员 | 派生类的保护成员 | 派生类的私有成员 |
保护成员变成 | 派生类的保护成员 | 派生类的保护成员 | 派生类的私有成员 |
私有成员变成 | 只能通过基类接口访问 | 只能通过基类接口访问 | 只能通过基类接口访问 |
能否隐式向上转换 | 是 | 是(但只能在派生类中) | 否 |
可以使用
using
重新定义访问权限,指出派生类可以使用特定的基类成员,即使采用的是私有派生。
Class Student : private std::string, private std:: valarry<double>
{
...
public:
using std:: valarry<double>::min;
};
上述
using
声明使得
valarry<double>::min
可用,就像他们是
Student
的公有方法一样。
注意
using
声明只使用成员名——没有圆括号、函数特征标和返回类型。
三、多重继承
C++引入多重继承的同时,引入了一种新技术——虚基类(virtual base class)。
class marketing : public virtual reality { ... };
多重继承会增加编程的复杂程度。这种复杂性主要是由于派生类通过多条途径继承同一个基类引起的。
四、类模板
C++的类模板为生成通用的类声明提供了一种更好的方法。
模板类以下面这样的代码开头(较新的C++实现允许使用
typename
代替
class
):
template <class Type>
类模板可以为类型参数提供默认值:
template <class T1, class T2 = int> class Topo { ... };
这样,如果省略T2的值,编译器将使用
int
。
由于模板不是函数,它们不能单独编译。模板必须与特定的模板实例化请求一起使用。为此,最简单的方法是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。
仅在程序包含模板并不能生成模板类,而必须请求实例化。为此,需要声明一个类型为模板类的对象,方法是使用所需的具体类型替换泛型名。
Stack<int> ker;
Stack<double> co;
看到上述声明后,编译器将按照
Stack<Type>
模板来生成两个独立的类声明和两组独立的类方法。
泛型标识符——例如这里的
Type
——被称为类型参数(type parameter),这意味着它们类似于变量,但赋给它们的不能是数字,而只能是类型。
可以将内置类型或类对象用作类模板
Stack<Type>
,但如果使用指针,在不对程序做重大修改的前提下,将无法很好的工作。
可以使用
typedef
为模板具体化指定别名:
typedef std::array<double, 12> arrd;
arrd gallons;//gallons的类型为std::array<double, 12>
C++新增了一项功能——使用模板提供一系列别名:
template<typename T>
using arrtype = std::array<T, 12>;
这将
arrtype
定义为一个模板别名,可以使用它来指定类型:
arrtype<double> gallons;
C++11允许将语法
using=
用于非模板,这时与常规
typedef
等价:
using pc2 = const char *;