函数模板与类模板知识点总结

一、函数模板

template <typename T> T max (T a, T b){
	return a>b ? a : b;
}

编译器编译到max(i1,i2)时,会根据模板实参生成一个具体函数,叫做函数模板实例化
实例化在编译阶段完成,在函数调用处发生
函数模板与函数重载
调用顺序:首先检查是否存在重载函数,若匹配成功则调用该函数,否则再去匹配函数模板

二、类模板

1.类模板定义

template <typename T>//模板形参表:用来说明一个或多个类型形参和普通形参;多个模板参数用逗号分隔
class TestClass {
public:
	T buffer[10];
	T getData(int j);
};
template <typename T>
T TestClass<T>::getData(int j) {
	return *(buffer + j);
};

2.类模板实例化:提供模板参数,以便编译器可以生成实际的类

类模板实例化只在需要类定义的时候才会发生!

void main() {
	TestClass<char> ClassInstA;
	TestClass<double> ClassInsB;
	TestClass<int> ClassInsC;
}

函数声明,不需要类定义,不需要实例化
定义引用,不需要类定义,不需要实例化
定义指针,不需要类定义,不需要实例化
定义类对象,需要类定义,需要实例化
访问指针指向的类对象,需要类定义,需要实例化
sizeof需要有类定义才能知道对象大小,需要类定义,需要实例化

template<typename Type> class Graphics {};
void f1(Graphics<char>);
class Rect {
	Graphics<double>& rsd;
	Graphics<int> si;
};
void main() {
	Graphics<char>* sc;
	f1(*sc);
	int iobj = sizeof(Graphics<string>);
}

类模板也可以支持普通参数(非类型参数)

template <typename T, int i>
class TestClass {
public:
	T buffer[i];
	T getData(int j);
};
template <typename T, int i>
T TestClass<T,i>::getData(int j) {
	return *(buffer + j);
};
void main() {
	TestClass<char, 5> ClassInstA;
	char cArr[6] = "abcde";
	for (int i = 0; i < 5; i++)
		ClassInstA.buffer[i] = cArr[i];
	for (int i = 0; i < 5; i++) {
		char res = ClassInstA.getData(i);
		cout << res << " ";
	}
}

注意类外定义成员函数时参数列表需一致,以及声明方式

template <typename T, int i>
T TestClass<T,i>::getData(int j) {
	return *(buffer + j);
};

3.类模板的静态成员

类模板的静态成员是模板实例化类的静态成员,对于每一个实例化类,其所有的对象共享其静态成员
类TA和类TA可以认为是两个不同的类,他们的类对象不共享静态变量m_t1 !

#include<iostream>
using namespace std;
template<typename T>class TA {
public:
	static int m_t1;
	static T m_t2;
};
template<typename T> int TA<T>::m_t1 = 100;
template<typename T> T TA<T>::m_t2 = 0;
int main() {
	TA <int> iobj1, iobj2;
	TA <double> dobj1, dobj2;
	iobj1.m_t1++; iobj1.m_t2++;
	iobj2.m_t1++; iobj2.m_t2++;
	dobj1.m_t1++; dobj1.m_t2++;
	dobj2.m_t1++; dobj2.m_t2++;
	cout << TA<int>::m_t1 << " " << TA<int>::m_t2 << endl;
	cout << dobj1.m_t1 << " " << dobj2.m_t2 << endl;
	return 0;
}

结果:
102 2
102 2

4.类模板的成员函数

类模板的所有成员函数都是函数模板
类模板实例化时成员函数并不自动被实例化,只有函数调用时才被实例化

template<typename T> class MyStack {
public:
	void create();//虽然没有用到模板类型 T,但create()仍然是函数模板
	void push(const T item);
};
template<typename T> void MyStack<T>::create() {};
template<typename T> void MyStack<T>::push(const T item) {};
int main()
{
	MyStack<int> s1;
	s1.create();
}

类模板的成员函数也可以是另外一个函数模板

template<typename T> class MyStack {
public:
	template<typename U> void create(U a);
};
template<typename T> template<typename U> void MyStack<T>::create(U a){};

int main()
{
	MyStack<int> s1;
	s1.create(2.5);
}

普通类的成员函数也可以是函数模板

5.类模板与友元函数

如果类模板的友元函数是普通函数,则友元函数是该类模板任意类实例的友元

void create() {}
template<typename T> class MyStack {
public:
	friend void create();
};

如果友元函数是与类模板无关的模板函数,则友元函数的任意函数实例是任意类实例的友元

template<typename U> void create(U x) {};
template<typename T> class MyStack {
public:
	friend template<typename U> void create(U x);
};

例如:函数模板的实例 void create(int) 和 void create(char)都是类模板实例 MyStack, MyStack的友元函数
友元函数是与类模板有关的模板函数,则友元函数只是该类模板特定类实例的友元

template<typename U> void create(U x) {};
template<typename T> class MyStack {
public:
	friend void create<T>(T x);
};

6.类型参数检测与特例版本

类模板的类型参数往往在实例化时不允许用任意的类(类型)作为“实参"

template <typename T>
class stack {
	T data[20];
	int top{ 0 };
public:
	void showtop(void);
};
template <typename T> void
stack<T>::showtop(void) {
	cout << "Top_Member:" << data[top] << endl;
}
class complex {
public:
	double real, image;
};
//自定义类,表示复数
void main() {
	stack<int>i1;
	stack<char>c1;
	stack<float>f1;
	stack<complex>cp1;//ERROR! 实例化为complex型,但showtop函数里的输出操作符 << 并不支持complex类型
}

解决方案一:对complex类进行<<运算符重载
解决方案二:在statck类模板里填加showtop函数的特例版本专门支持complex类

void stack<complex>::showtop() {
	cout<<"Top_Member:"<<data[top].real<<' '<<data[top].image<<endl;
}

7.类模板的继承与派生

一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)

class CB { //基类CB 为一般类(其中不使用类型参数)
	...
};
//派生类CA为类模板,使用了类型参数T
template <typename T> class CA :public CB {
	T t; //派生类新加的成员
public:
	...
};

类模板作基类,派生出新的类模板,但仅基类中用到类型参数T,而派生的类模板中不使用T

template <typename T> class CB {
	T t;
public:
	T gett() { return t; }
};
template <typename T> class CA : public CB<T> {
	double t1; //派生类的新成员并不使用 T
	T t1;//派生类新填加的成员也使用了基类的模板类型T
};

类模板作基类,派生出新的类模板,但基类和派生类使用的类型参数不同

template <typename T2> class CB {
	T2 t2; //数据类型为T2
public:
	...
};
template <typename T1, typename T2>class CA :
	public CB<T2> {
	T1 t1; //数据类型为T1
};
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值