c++primer plus第十四章-多重继承、模板类

c++primer plus第十四章-多重继承、模板类

1)虚基类

虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。

class Singer : virtual public Worker {... ...}

class Waiter : public virtual Worker {... ...}

class SingingWaiter : public Singer , public Waiter {... ...};

SingingWaiter对象都只包含Worker对象的一个副本。继承的Singer和Waiter对象共享一个Worker对象,而不是各自引入自己的Worker对象副本。


2)如果不希望默认构造函数来构造虚基类对象,则需要显式地调用所需的基类构造函数。因此,构造函数应该这样:

SingingWaiter(const Worker & wk, int p=0, int v=Singer :: other) : Worker(wk), Waiter(wk, p), Singer (wk, v){...}

这将显式调用构造函数worker(const Worker &)。对于虚基类,必须这样做,对于非虚基类,则是非法的。


如果类有间接虚基类,则除非只需使用该虚基类的默认构造函数,否则必须显式地调用该虚基类的某个构造函数。


3)虚基类:主要变化(同时也是使用虚基类的原因)是,从虚基类的一个或多个实例派生而来的类将只继承了一个基类对象。为实现这种特性,必须满足其他要求:

第一:有间接虚基类的派生类包含直接调用间接基类构造函数的构造函数,这对于间接非虚基类来说是非法的。

第二:通过优先规则解决名称二义性。


4)类模板

template <class Type>

关键字template告诉编译器,将要定义一个模板。尖括号中的内容相当于函数的参数列表。可以把关键字class看作是变量的类型名,该变量接受类型作为其值,把Type看作是该变量的名称。

这里使用class并不是意味着Type必须是一个类;而只是表面Type是一个通用的类型说明符,在使用模板时,将使用实际的类型替换它。

也可以这样:

template <typename Type>

可以使用自己的泛型名代替Type,当目标被调用时,Type将被具体的类型值取代。


5)可以使用模板成员函数替换原来类的类方法,每个函数头都将以相同的模板声明打头:

bool Stack :: push(const Item & item)

{... ...}

应该为:

template<class Type>

bool Stack<Type> :: push(const Type & item)

{... ...}


6)使用模板类

泛型标识符Type称为类型参数,这意味着它们类似于变量,但是赋给它们的不能是数字,而只能是类型。必须显式地提供所需的类型,这与常规的函数模板不同,因为编译器可以根据函数的参数类型来确定要生成哪种函数。


7)使用指针栈的方法之一是,让调用程序提供一个指针数组,其中每个指针都指向不同字符串,把这些指针放在栈中是有意义的。因为每个指针都将指向不同的字符串。注意,创建不同指针是调用程序的职责,而不是栈的职责。栈的任务是管理指针,而不是创建指针。


8)递归使用模板

ArrayTP<ArrayTP<int, 5>, 10> twodee;

这使得twodee是一个包含10个元素的数组,其中每个元素都是一个包含5个int元素的数组,与之等价的常规数组时:

int twodee[10][5];


9)默认类型模板参数

template<class T1, class T2 = int> 

class Topo

{... ...}

如果省略了T2的值,编译器将使用int

Topo<double , double> m1;

Topo<double> m2;//T1 is double, T1 is int

虽然可以为类模板类型参数提供默认值,但不能为函数模板参数提供默认值。然而,可以为非类型参数提供默认值。


10)模板的隐式实例化

即它们声明一个或多个对象,指出所需的类型,而编译器使用通用模板提供的处方生成具体的类定义。

ArrayTP<int, 100> stuff;  //隐式定义

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

ArrayTP<double, 30> *pt; //a pointer, no object needed yet

pt = new ArrayTP<double , 30>;  //now , an object is needed


11)模板的显示实例化

当使用关键字template并指出所需类型来声明类时,编译器将生成类声明的显示实例化。声明必须位于模板定义所在的名称空间中。

template class ArrayTP<string ,100>; //generate ArrayTP<string,100> class

在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。


12)模板的显式具体化

是特定类型(用于替换模板中的泛型)的定义。有时候,需要在为特殊类型实例化时,对模板进行修改,使其行为不同。

template <typename T>

class SortedArray

{... ...}


template<> class SortedArray<const char char *>

{... ...}


13)模板的部分具体化

即部分限制模板的通用性。部分具体化可以给类型参数之一指定具体的类型:

template <class T1, class T2>

class Pair<T1, int>

{... ...}//具体化了T2。


14)如果有多个模板可供选择,编译器将使用具体化程度最高的模板。

也可以通过为指针提供特殊版本来部分具体化现有的模板:

template<class T>

class Feeb {... ...};

template<class T*>

class Feeb {... ...};

如果提供的类型不是指针,则编译器将使用普通版本;如果提供的是指针,则编译器将使用指针具体化版本;

Feeb<char> fb1;

Feeb<char *> fb2;

如果没有进行部分具体化,则第二个声明将使用通用版本,将T转换为char * 类型。如果进行了部分具体化,则第二个声明将使用具体化版本,将T转换为char。


15)部分具体化可以设置各种限制

//generate template

template <class T1, class T2, class T3>  class Trio{...};

//specialization with T3 set to T2

template <class T1, class T2 >  class Trio<T1, T2, T3>{...};

//specialization with T3 and T2 set to T1*

template <class T1>  class Trio<T1, T1* , T1*>{...};

给定上述声明,编译器将作出如下选择:

Trio<int , short, char *> t1;// use general template

Trio<int , short> t2;// use Trio<T1, T2, T3>

Trio<char, char *, char *> t3;// use Trio<T1, T1* , T1*>



你可能感兴趣的:(C++,C语言)