C++中的代码重用与其他

当初始化列表包含多个项目时,这些项目被初始化的顺序为他们被声明的顺序,而不是他们在初始化列表中的顺序。

1、私有继承

使用私有继承,基类的公有成员和保护成员都将称为派生类的私有成员。使用公有继承,基类的公有方法将称为派生类的公有方法;使用私有继承,基类的公有方法将称为派生类的私有方法,派生类不继承基类的接口,这种不完全继承是has-a关系的一部分。

使用私有继承,类将继承实现。例如从String中派生出一个Student类,派生类将有一个String类组件用于保存字符串,另外STudent方法可以使用String的方法来访问String组件。

2、保护继承

使用保护继承,基类的公有成员和保护乘员都将称为派生类的保护成员。

3、多重继承

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

class worker
{};
 
class singer : virtual public worker
{};
 
class waiter : public virtual worker
{};
 
class SingingWaiter : public singer, public waiter
{};

使用虚基类需要对C++规则进行调整:新的构造函数规则

使用虚基类时,需要对类构造函数采用一种新的方法。C++在基类是虚的时,禁止信息通过中间类自动传递给基类,编译器必须在构造派生对象之前构造基类的对象组件,所以编译器会调用虚基类的默认构造函数,或者要显式调用所需的基类构造函数。

class SingingWaiter : public singer, public waiter
{
public:
	SingingWaiter(const worker &wk, int n, double k)
		:worker(wk), singer(n), waiter(k)
	{}
};

除了修改类构造函数规则外,还要调整其他代码解决多重继承可能导致函数调用的二义性问题。我们可以在派生类中重新定义方法来指出要使用哪个。

4、类模板

以下是一个类模板示例:

template 
class Stack
{
public:
	Stack();
	bool isempty() const;
	bool isfull() const;
	bool push(const Type & item);
	bool pop(Type &item);
private:
	enum { MAX = 10 };
	Type items[MAX];
	int top;
};
 
template 
Stack::Stack()
{
	top = 0;
}
 
template 
bool Stack::isempty() const
{
	return top == 0;
}
 
template 
bool Stack::isfull() const
{
	return top == MAX;
}
 
template 
bool Stack::push(const Type & item)
{
	if (top < MAX)
	{
		items[top++] = item;
		return true
	}
	else
	{
		return false;
	}
}
 
template 
bool Stack::pop(Type &item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
	{
		return false;
	}
}

4.1、数组模板示例和非类型参数

模板常用作容器类,有两种方法可以指定数组大小的简单数组模板:

在类中使用动态数组和构造函数参数来提供元素数目;

使用模板参数来提供常规数组的大小:

template 
class MyArray
{
private:
	Type array[n];
};

4.2、模板多功能性

模板类可以用作基类,也可用作组件类,还可用作其他模板的类型参数。

template 
class MyArray
{
private:
	Type entry[n];
};
 
template 
class GrowArray : public MyArray
{
 
};

1、递归使用模板:

MyArray, 10> ar;
// int arr[10][5]

声明了一个包含10个元素的数组,每个元素都是一个包含5个int元素的数组。

2、使用多个类型参数:

3、默认类型模板参数

template 
class to
{};

4.3、模板具体化

1、隐式具体化:声明一个对象,指出所需类型

MyArray, 10> *ar;
arr = new MyArray, 10>;

编译器在需要对象之前,不会生成类的隐式实例化,即运行到上面第二句才会生成类定义。

2、显式具体化:使用template并指出所需类型来声明类,声明必须位于模板定义所在的命名空间中

3、显式具体化:特定类型的定义(用于需要为特殊类型实例化,对模板进行修改,使其行为不同)

template 
class MyArray
{
public:
	MyArray() {
		for (size_t i = 0; i < n; i++)
		{
			entry[i] = n;
		}
	}
	void print() const {
		for (size_t i = 0; i < n; i++)
		{
			cout << "n = " << n << " ," << " entry = " << entry[i] << endl;
		}
	}
private:
	Type entry[n];
};
 
 
template<> class MyArray
{
public:
	MyArray() {
		for (size_t i = 0; i < 5; i++)
		{
			entry[i] = i;
		}
	}
	void print() const {
		for (size_t i = 0; i < 5; i++)
		{
			cout << "n[" << i << "]" << " = " << entry[i] << endl;
		}
	}
private:
	double entry[5];
};
 
	MyArray arr;
	arr.print();
 
/*
n[0] = 0
n[1] = 1
n[2] = 2
n[3] = 3
n[4] = 4
*/

4、部分具体化:部分限制模板的通用性

template 
class A
{};
 
template  class A
{};

4.4、成员模板

模板可用作结构、类或模板类的成员。要完全实现STL的设计,必须使用这项特性。

template 
class beta
{
private:
	template 
	class hold
	{
	private:
		V val;
	public:
		hold(V v = 0) :val(v) {}
		void show() const { cout << val << endl; }
		V Value() const { return val; }
	};
	hold q;
	hold n;
public:
	beta(T t, int i) :q(t), n(i) {}
	template
	U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
	void show() const { q.show(); n.show(); }
};
 
beta guy(3.5, 3);

这里要看的是blab方法,blab方法的U类型由该方法被调用时的参数值显式确定,T类型由对象的实例化类型确定。

cout << guy.blab(3, 2.1) << endl;

上面的这种调用方式将会返回一个int类型的值。

4.5、将模板用作参数

template 
class King
{
 
};
 
template