【C++类模板】

C++类模板

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

`关于类模板的一些问题


一、类模板的基本用法

类模板:创建一个通用的类,类中成员的类型未指定是哪一种具体类型,用一个虚拟的类型来代表
格式:

template <typename T>

提示:
template是声明模板的创建
typename也可用class代替,两者没区别
T是通用的数据类型,也可用其他字母代替,一般是大写

示例:

//类模板
template<typename T1, typename T2>
class Student
{
public:
	Student(T1 name, T2 id)
	{
		this->m_name = name;
		this->m_id = id;
	}

	void show()
	{
		cout << "name: " << this->m_name << "id: " << this->m_id << endl;
	}

	T1 m_name;
	T2 m_id;
};


void test()
{
	Student<string, int> p("张三", 18);
	p.show();
}
   
int main()
{
	test();
	system("pause");
	return 0;
}


二、类模板与函数模板的区别

类模板与函数模板的区别:
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数
3.类模板在实例化时必须显式地指明数据类型,编译器不能根据给定的数据推演出数据类型

示例:

template<typename T1, typename T2 = int> //缺省
class Student
{
public:
	Student(T1 name, T2 id)
	{
		this->m_name = name;
		this->m_id = id;
	}

	void show()
	{
		cout << "name: " << this->m_name << "id: " << this->m_id << endl;
	}

	T1 m_name;
	T2 m_id;
};


void test1()
{
	Student<string, int> p("张三", 18);//必须显式类型推导
	p.show();
}

void test2()
{
	Student<string> p("李四",20);//类模板参数列表已经进行缺省,故只写了string就可以
}
int main()
{
	test1();
	system("pause");
	return 0;
}

三、类模板中成员函数创建时机

类模板中成员函数与普通类中成员函数的创建时机是不同的:
——普通类的成员函数在编译时就已经创建
——类模板的成员函数在调用时才创建

示例:

#include <iostream>

using namespace std;
class person1
{
public:
    void show1()
    {
        cout <<"我是person1"<<endl;
    }
};

class person2
{
    void show2()
    {
        cout <<"我是person2"<<endl;
    }
};

template <class T>
class usePerson
{
public:
    T per;
    //类模板中的成员函数,不是一开始就创建了,类模板调用时候创建
    void fun1()
    {
        per.show1();
    }
    void fun2()
    {
        per.show2();
    }

};

四、类模板中成员函数在类外如何实现

类模板的成员函数在类内声明,在类外如何实现的呢?

示例:

template <class T1,class T2>
class MM
{
public:
	MM(T1 one,T2 two) :one(one),two(two){}
	void print();   //函数类内声明
protected:
		T1 one;
		T2 two;
};

template <class T1class T2>        //注意:这里也要写明template
void MM<T1,T2>::print()     //这里不仅要写明作用域,还要写<T1,T2>
{
	cout << one << endl;
	cout << two << endl;
}

五、类模板对象作为函数参数的实现

三种传入方式:
1.指定传入类型
2.参数模板化
3.整个类进行模板化

示例:

#include<iostream>
using namespace std;

template<class T1,class T2>
class Person
{
public:
	Person(T1 name,T2 age)
	{
		this->m_name = name;
		this->m_age = age;
	}

	void showPerson()
	{
		cout << "姓名: " << m_name << "  " << "年龄: " << m_age << endl;
	}
public:
	T1 m_name;
	T2 m_age;
};

//1.指定传入类型
void printPerson01(Person<string,int>& p)
{
	p.showPerosn();
}
void test01()
{
	Person<string,int>p("张三",23);
	//p.showPerson();
	printPerson01(p);
}

//2.参数模板化
template<class T1,class T2>
void printPerson02(Person<T1,T2>&P)
{
	p.showPerson();
}
void test02()
{
	Person<string,int>p("李四",34);
	printPerson02(p);
}

//3.整个类进行模板化
template<class T>
void printPerson03(T & p)
{
	p.showPerson();
}
void test03()
{
	Person<string,int>p("王五",56);
	printPerson03(p);
}

int main()
{
	//test01();//用哪个时开哪个(因为我起的对象名都是p)
	//test02();
	test03();

	system("pause");
	system("cls");
}

六、类模板继承

1.普通子类继承类模板: 格式:class 子类:public 父类<指定类型> //这里指定类型,必须告诉Base中T的类型,否则T无法分配内存

2.类模板继承类模板 格式: template<class T1,class T2>
class son: public person<T1,T2> {}

示例:

//类模板与继承
template<class T>
class Parent
{
	T m;
};

//class Son: public Parent//错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Parent<int>
{

};

void test01()
{
	Son s1;
}

//如果想灵活指定父类中T的类型,子类也需要变成类模板
template<class T1,class T2>
class Son2 : public Parent<T2>
{
public:
	Son2()
	{
		cout << "T1的类型为:" << typeid(T1).name() << endl;
		cout << "T2的类型为:" << typeid(T2).name() << endl;

	}
	T1 obj;
};

void test02()
{
	Son2<int,char> s2;
}

int main()
{
	test02();
	
	system("pause");
	return 0;
}

七、类模板分文件编写

解决方案:
1.当类模板的声明与实现分开始,main.cpp中需要包含(include) .cpp文件
2.也可以把声明和实现写到一个文件中,此文件后缀名为 .hpp

八、类模板与友元

有两种实现方式:
1.类内实现友元函数(直接类内声明即可)
2.类外实现友元函数(需要提前让编译器知道全局函数的存在)

示例:1.类内实现


template<class T1, class T2>
class Person
{
	//全局函数类内实现
	friend void printPerson(Person<T1, T2> p)
	{
		cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
	}
public:
	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	
private:
	T1 m_Name;
	T2 m_Age;
};

void test01()
{
	Person<string, int>p("Tom", 30);
	printPerson(p);
}
int main()
{
	test01();
	
	system("pause");
	return 0;
}

2.类外实现

//提前让编译器知道Person类的存在
template<class T1, class T2>
class Person;

//类外实现
template<class T1, class T2>
void printPerson(Person<T1, T2> p)
{
	cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
	//全局函数类外实现 
	//加空模板参数列表
	//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson<>(Person<T1, T2> p);
public:
	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	
private:
	T1 m_Name;
	T2 m_Age;
};



void test01()
{
	Person<string, int>p("Tom", 30);
	printPerson(p);
}


int main()
{
	test01();
	
	system("pause");
	return 0;
}

九、类模板的特化

类模板的特化:
1.完全特化
2.局部特化

template <class T1,class T2,class T3>
	class Data
	{
	public:
		Data(T1 one,T2 two,T3 three) : one(one),two(two),three(three)
		{
			cout << "原生模板" << endl;
		}
	protected:
		T1 one;
		T2 two;
		T3 three;
	};
	
//完全特化:
	template<>
	class Data<int,string,string>
	{
	public:
		Data(int one,string two,string three) : one(one),two(two),three(three)
		{
			cout << "完全特化" << endl;
		}
	protected:
		int one;
		string two;
		string three;
	};
//局部特化:
template <class T1>
	class Data<T1,T1,T1>
	{
	public:
		Data(T1 one,T1 two,T1 three) : one(one),two(two),three(three)
		{
			cout << "局部特化" << endl;
		}
	protected:
		T1 one;
		T2 two;
		T3 three;
	};
	调用时:
	Data<int,string,string> data1(1,"张三","李四"); //肯定调用的是完全特化
	Data<string,int,string> data2("王五",5,"李四");  //在特化中没找到与之匹配的模板,肯定调用的是原生模板
	Data<string,string,string> data3("王五","张三","李四"); //肯定调用的是局部特化

十、关于类模板需要注意的一些点

1.类模板在调用时,必须显式调用,不能隐式调用(即类模板必须显式实例化)
2.类模板没有自动类型推导的使用方式
3.类模板不是一个完整类,所以在用到类名的地方,必须要用类名<类型>方式去使用 (需要时刻注意)
4.类模板也能传入常量 如: template <class T1,int size> class array1 { … };

注:本文参考b站C++网课视频

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值