C++小记(七)

关键词:模版

C++提供两种模板机制:函数模板、类模板,使得程序(算法)可以从逻辑功能上抽象,把被处理的对象(数据)类型作为参数传递。

模板把函数或类要处理的数据类型参数化,表现为参数的多态性,称为类属。模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。

函数模板(function template)

  所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

   

template <typename T>                    //模版,固定形式,不加“;”
T add(T x, T y)                          //函数模版
{
	return x + y;
}

template <typename T1, typename T2>       //模版可定义多种类型
void print(T1 x,T2 y)
{
	cout << "template <typename T1, typename T2>" << endl;
	cout << x << "     " << y << endl;
}

/*****************************************************************/

//main.cpp
int main()
{
	int a = 1, b = 2;
	double c = 2.2, d = 3.3;

	cout << add(a, b) << endl;            //函数模版,隐式调用,函数根据参数类型调用模版
	cout << add(c, d) << endl;
	cout << add<int>(a, b) << endl;       //显式调用

	//cout << add<int>(a, c) << endl;     //两个参数类型不一致时,一定要显式调用
	
	print(a, c);                  //隐式调用,当函数模版遇到同名的普通函数,优先调用普通函数
	print<int , double>(a, c);    //显示调用则调用的是函数模版
	                              //普通函数存在默认的类型转换(int和char),函数模版不行
	print(a, b, c);               //函数模版也和普通函数一样可以重载
	system("pause");
	return 0;
}

几个注意点:

  1. 普通函数存在默认的类型转换(int和char),函数模版不行
  2. 两个参数类型不一致时,一定要显式调用
  3. 隐式调用,当函数模版遇到同名的普通函数,优先调用普通函数
  4. 编译器并不是把函数模板处理成能够处理任意类的函数,编译器从函数模板通过具体类型产生不同的函数,会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

类模板

   类模板用于实现类所需数据的类型参数化 ,类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响

template <typename T>
class A
{
protected:
	T m_a;
public:
	A(T a);
};

template <typename T>
A<T>::A(T a)
{
	m_a = a;
}

class B : public A<int>    //模板类派生普通类
{
private:
	int m_b;
public:
	B(int b);
};

template <typename T, typename T2>
class C : public A<T2>     // 模板类派生模板类
{
private:
	T m_c;
public:
	C(T c, T2 a);
	void print();
};

template <typename T, typename T2>
C<T, T2>::C(T c, T2 a) : A<T2>(a)
{
	m_c = c;
}

int main()
{
	B b(1);
	C<int, double> c(1, 1.00);    //模板类一定要显式调用

	return 0;
}

以上代码是单个类模板的语法

 类模板一定要显式调用 ,不然编译会报错          


类模板的几个重要事项

用友元函数重载 << >>

friend ostream& operator<< <T> (ostream &out, Complex<T> &c3) ;


友元函数:友元函数不是实现函数重载(非 << >>)
1)需要在类前增加 类的前置声明 函数的前置声明 
               

template<typename T>
class Complex;  
template<typename T>
Complex<T> mySub(Complex<T> &c1, Complex<T> &c2);


2)类的内部声明 必须写成: 

friend Complex<T> mySub <T> (Complex<T> &c1, Complex<T> &c2);


3)友元函数实现 必须写成:

  template<typename T>
  Complex<T> mySub(Complex<T> &c1, Complex<T> &c2)
  {
    Complex<T> tmp(c1.a - c2.a, c1.b-c2.b);
    return tmp;
  }


4)友元函数调用 必须写成

Complex<int> c4 = mySub<int>(c1, c2);
cout<<c4;

结论:友元函数最好只用来进行 左移 友移操作符重载。

类模板中的static:

  • 从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
  •  和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
  •  每个模板类有自己的类模板的static数据成员副本

猜你喜欢

转载自blog.csdn.net/userkiller/article/details/81346489