最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

世界热议:62.类模板

来源:博客园

1.类模板

1.1类模板基本概念

函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板

●类模板用于实现类所需数据的类型参数化

templateclass Person{public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}public:NameType mName;AgeType mAge;};void test01(){//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 PersonP1("德玛西亚", 18);P1.showPerson();}

1.2类模板做函数参数

//类模板templateclass Person{public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void PrintPerson(){cout << "Name:" << this->mName << " Age:" << this->mAge << endl;}public:NameType mName;AgeType mAge;};//类模板做函数参数void DoBussiness(Person& p){p.mAge += 20;p.mName += "_vip";p.PrintPerson();}int main(){Person p("John", 30);DoBussiness(p);system("pause");return EXIT_SUCCESS;}
#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#include//普通类继承类模版templateclass Father{public:Father(){m = 20;}public:T m;};//普通类 继承 类模版class Son :public Father//要告诉编译器父类的泛型数据类型具体是什么类型{public:};//类模版 继承 类模版templateclass Son2 :public Father//要告诉编译器父类的泛型数据类型具体是什么类型{};void test(){Son2 s;cout << s.m << endl;}int main(){test();system("pause");return EXIT_SUCCESS;}

3.类模板派生普通类

#pragma warning(disable:4996)#define _CRT_SECURE_NO_WARNINGS 1#include #include using namespace std;//类模板templateclass MyClass {public:MyClass(T property) {this->mProperty = property;}public:T mProperty;};//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的//这样c++编译器才能知道给子类分配多少内存//普通派生类class SubClass : public MyClass {public:SubClass(int b) : MyClass(20) {this->mB = b;}public:int mB;};int main(){SubClass son(1);cout << "son.mProperty:" << son.mProperty << "," << "son.mB:" << son.mB << endl;    system("pause");    return EXIT_SUCCESS;}

输出:


(资料图片仅供参考)

son.mProperty:20,son.mB:1请按任意键继续. . .

1.4模板派生类模板

//父类类模板templateclass Base{T m;};templateclass Child2 : public Base  //继承类模板的时候,必须要确定基类的大小{public:T mParam;};void test02(){Child2 d2;}

1.5类模板类内实现

templateclass Person{public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}public:NameType mName;AgeType mAge;};void test01(){//Person P1("德玛西亚",18); // 类模板不能进行类型自动推导 PersonP1("德玛西亚", 18);P1.showPerson();}
#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#includetemplateclass Maker{public:Maker(NameType name, AgeType age);/*{this->name = name;this->age = age;}*/void printMaker();/*{cout << "Name:" << this->name << " Age:" << this->age << endl;}*/public:NameType name;AgeType age;};//类模版的成员函数类外实现//要写成函数模版templateMaker::Maker(NameType name, AgeType age){cout << "构造函数" << endl;this->name = name;this->age = age;}templatevoid Maker::printMaker(){cout << "Name:" << this->name << " Age:" << this->age << endl;}int main(){Maker m("haha", 20);m.printMaker();system("pause");return EXIT_SUCCESS;}

1.6类模板类外实现

#define _CRT_SECURE_NO_WARNINGS#include#includeusing namespace std;templateclass Person{public:Person(T1 name, T2 age);void showPerson();public:T1 mName;T2 mAge;};//类外实现templatePerson::Person(T1 name, T2 age){this->mName = name;this->mAge = age;}templatevoid Person::showPerson(){cout << "Name:" << this->mName << " Age:" << this->mAge << endl;}void test(){Person p("Obama", 20);p.showPerson();}int main(){test();system("pause");return EXIT_SUCCESS;}

1.7类模板头文件和源文件分离问题

Person.hpp

#pragma oncetemplateclass Person{public:Person(T1 name,T2 age);void ShowPerson();public:T1 mName;T2 mAge;};templatePerson::Person(T1 name, T2 age){this->mName = name;this->mAge = age;}templatevoid Person::ShowPerson(){cout << "Name:" << this->mName << " Age:" << this->mAge << endl;}

main.cpp

#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#include#include"Person.hpp"//模板二次编译//编译器编译源码 逐个编译单元编译的int main(){Person p("Obama", 20);p.ShowPerson();system("pause");return EXIT_SUCCESS;}

结论:案例代码在qt编译器顺利通过编译并执行,但是在Linux和vs编辑器下如果只包含头文件,那么会报错链接错误,需要包含cpp文件,但是如果类模板中有友元类,那么编译失败!

解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).

原因:

类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。

C++编译规则为独立编译

1.8模板类碰到友元函数

#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#include template class Person;//告诉编译器这个函数模板是存在template void PrintPerson2(Person& p);//友元函数在类内实现templateclass Person{//1. 友元函数在类内实现friend void PrintPerson(Person& p){cout << "Name:" << p.mName << " Age:" << p.mAge << endl;}//2.友元函数类外实现//告诉编译器这个函数模板是存在friend void PrintPerson2<>(Person& p);//3. 类模板碰到友元函数模板templatefriend void PrintPerson(Person& p);public:Person(T1 name, T2 age){this->mName = name;this->mAge = age;}void showPerson(){cout << "Name:" << this->mName << " Age:" << this->mAge << endl;}private:T1 mName;T2 mAge;};void test01(){Person p("Jerry", 20);PrintPerson(p);}// 类模板碰到友元函数//友元函数类外实现  加上<>空参数列表,告诉编译去匹配函数模板templatevoid PrintPerson2(Person& p){cout << "Name2:" << p.mName << " Age2:" << p.mAge << endl;}void  test02(){Person p("Jerry", 20);PrintPerson2(p);   //不写可以编译通过,写了之后,会找PrintPerson2的普通函数调用,因为写了普通函数PrintPerson2的声明}int main(){//test01();test02();system("pause");return EXIT_SUCCESS;}
#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#includetemplateclass Maker{friend void printMaker(Maker &p){cout << "类内实现" << p.name << " " << p.age << endl;}public:Maker(NameType name, AgeType age){this->name = name;this->age = age;}private:NameType name;AgeType age;};void test01(){Maker m("悟空", 18);printMaker(m);}templateclass Maker2;//告诉编译器下面有printMaker2的实现templatevoid printMaker2(Maker2 &p);templateclass Maker2{//1.在函数名和()之间加上<>。(使得可以去找函数模板)friend void printMaker2<>(Maker2 &p);//2.编译器不知道printMaker2下面有没有实现,需要知道函数的结构public:Maker2(NameType name, AgeType age){this->name = name;this->age = age;}private:NameType name;AgeType age;};//友元在类外实现要写成函数模版templatevoid printMaker2(Maker2 &p){cout << "类外实现的友元函数 " << p.name << " " << p.age << endl;}void test02(){Maker2 m("贝吉塔", 18);printMaker2(m);}int main(){test02();system("pause");return EXIT_SUCCESS;}

2.类模板的应用

设计一个数组模板类(MyArray),完成对不同类型元素的管理

类模版实现数组.cpp

#define _CRT_SECURE_NO_WARNINGS#includeusing namespace std;#include"MyArray.hpp"#includeclass Maker{public:Maker(){}Maker(string name, int age){this->name = name;this->age = age;}public:string name;int age;};void printMaker(MyArray &arr){for (int i = 0; i < arr.getSize(); i++){cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << endl;}}void test(){MyArray myarr(4);Maker m1("悟空", 18);Maker m2("贝吉塔", 30);Maker m3("短笛", 200);Maker m4("小林", 19);myarr.Push_Back(m1);myarr.Push_Back(m2);myarr.Push_Back(m3);myarr.Push_Back(m4);printMaker(myarr);MyArray myint(10);for (int i = 0; i < 10; i++){myint.Push_Back(i + 1);}for (int i = 0; i < 10; i++){cout << myint[i] <<" ";}cout << endl;}int main(){test();system("pause");return EXIT_SUCCESS;}

MyArray.hpp

#pragma oncetemplateclass MyArray{public:MyArray(int capacity){this->mCapacity = capacity;this->mSize = 0;//T如果是Maker,这里要调用什么构造函数,要调用无参构造p = new T[this->mCapacity];}//拷贝构造MyArray(const MyArray &arr){this->mCapacity = arr.mCapacity;this->mSize = arr.mSize;p = new T[arr.mCapacity];for (int i = 0; i < this->mSize; i++){p[i] = arr.p[i];}}//赋值函数MyArray &operator=(const MyArray &arr){if (this->p != NULL){delete[] this->p;this->p = NULL;}p = new T[arr.mCapacity];this->mSize = arr.mSize;this->mCapacity = arr.mCapacity;for (int i = 0; i < this->mSize; i++){p[i] = arr.p[i];}return *this;}//重载[]T &operator[](int index){return this->p[index];}//尾插void Push_Back(const T &val){if (this->mSize == this->mCapacity){return;}this->p[this->mSize] = val;this->mSize++;}//尾删void Pop_Back(){if (this->mSize == 0){return;}this->mSize--;}~MyArray(){if (this->p != NULL){delete[] p;p = NULL;}}int getSize(){return this->mSize;}private:T *p;int mCapacity;int mSize;};

关键词: