第十四章 C++中的代码重用
内容包括
has-a关系
包含对象成员的类
模板类valarray
私有和保护继承
多重继承
虚基类
创建类模板
使用类模板
模板的具体化
1.valarray类简介:
头文件valarray支持,用于处理数值或具有类似特性的类。被定义为模板类,以便能够处理不同的数据类型。
可以创建长度为零的空数组、指定长度的空数组、所有元素被初始化为指定值的数组、用常规数组中的值进行初始化的数组。
vector和array有着类似的创建语法,这些类也可以用来存储数字,但它们提供的算术支持没有valarray多。
2.double gpa[5]={3.1,3.5,3.8,2.9,3.3};
valarray<double>v1;//size 0
valarray<int>v2(8)//8 int elements
valarray<int>v3(10,8);//8 int elements,each set to 10
valarray<double>v4(gpa,4);
//initialized to the first 4 elements of gpa
3.operator[]():让您能够访问各个元素
size():返回包含的元素数
sum():返回所有元素的总和
max():返回最大的元素
min():返回最小的元素
4.has_a关系将数据成员声明为私有的。student类的成员函数可以用string和valarray<double>类的公有接口来访问和修改name和score对对象,只能通过student类的公有接口来访问name和score,student类获得了其成员对象的实现,但没有继承接口。
5.使用公有继承,类可以继承接口和实现,而使用组合,类可以获得实现,但不能获得接口。不继承接口是has_a关系的组成成分。
6.接口的定义和实现:
所谓的接口,即将内部实现细节封装起来,外部用户用过预留的接口可以使 用接口的功能而不需要知晓内部的具体细节。
7.可以用一个参数调用的构造函数将用作从参数类型到类类型的隐式转换函数,但这通常不是好主意,所以可以使用explicit关键字来关闭隐式转换。
8.C++包含让程序员能够限制程序结构的特性:explicit防止单参数构造函数的隐式转换,const限制方法修改数据。
9.初始化顺序:
在初始化列表包含多个项目的时候,初始化的顺序是他们被声明的顺序
当代码使用一个成员的值作为另一个成员初始化表达式的一部分时,初始化顺序非常重要。
10.另一种实现has_a的途径是私有继承
11.使用多个基类的继承被称为多重继承(MI)。
MI尤其是公有MI将导致一些问题,必须用额外的语法规则来解决它们。
12.对于继承类,新版本的构造函数将使用成员初始化列表语法,它使用类名而不是成员名来标识构造函数:
Student (const char*str,const double * pd,int n)
:std::string(str),ArrayBd(pd,n){}
13.访问基类对象:
使用私有继承时,string对象没有名称,如何访问内部的string对象呢
答案是使用强制类型转换。
可以通过强制类型转换,将Student对象转换为string对象,结果是继承而来的string对象
const string& Student::Name()const
{
return (const string&)*this;
}
14.访问基类的友元函数
用类名显式地限定函数名不适合于友元函数,这是因为友元不属于类,然而,可以通过显式地转换为基类来调用正确的函数。
ostream&operator<<(ostream&os,const Student&stu)
{
os<<"Scores for "<<(const String&)stu<<":\n";
}
15.多重继承:两个主要的问题
(1)从两个不同的基类继承同名方法
(2)从两个或更多相关基类继承同一个类。
16.通常可以将派生类对象的地址赋给基类指针,但在多重继承的情况下会导致二义性,派生类中包含两个基类对象,有两个地址可供选择,所以应使用类型转换来指定对象:
Worker*pw1=(Waiter*)&ed;//the Worker in Waiter
Worker*pw2=(Singer*)&ed;//the Worker in Singer
17.虚基类:
虚基类使得从多个类(它们的基类相同)派生的对象只继承一个基类对象。通过在类声明中使用关键字virtual,可以使Worker被用作Singer和Waiter的虚基类
在虚函数和虚基类之间并不存在明显的联系。
C++在基类是虚的时候,禁止信息通过中间类自动传递给基类
SingingWaiter(const Worker&wk,int p=0,int v=Singer::other)
:Waiter(wk,p),Singer(wk,v){}//flawed
SingingWaiter(const Worker&wk,int p=0,int v=Singer::other)
:Worker(wk),Waiter(wk,p),Singer(wk,v){}
18.哪个方法:
对于单继承,如果没有重新定义Show(),则将使用最近祖先中的定义。而在多重继承中,有多个最近祖先。使得调用具有二义性。
可以用作用域解释符来澄清编程者的意图,然而,更好的方法是在SingingWaiter中重新定义Show(),并指出要使用哪个Show( ).
19.C-风格字符串库函数strchr()
while(strchr("wstq",choice)==NULL)
该函数返回参数choice指定的字符在字符串“wstq”中第一次出现的地址,如果没有这样的字符,返回NULL指针。
20.类模板:
模板提供参数化(parameterized)即能够将类型名作为参数传递给接收方来建立类或函数。
21.template<class Type>
每个函数头都由相同的模板声明打头
22.使用多个类型参数(pair模板)
假设希望类可以保存两种值,则可以创建并使用Pair模板来保存两个不同的值(标准模板库提供了类似的模板,名为pair.)
23.class Pair
{
private:
T1 a;
T2 b;
public:
T1&first();
T2&second();
T1 first()const{return a;}
T2 second()const{return b;}
Pair(const T1&aval,const T2&bval):a(aval),b(bval){}
Pair(){}
};
template<class T1,class T2>
T1&Pair<T1,T2>::first()
{
return a;
}
template<class T1,class T2>
T2&Pair<T1,T2>::second()
{
return b;
}