在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理C++知识点的第二十一篇博客。
本篇博客介绍了C++的类模板。
本系列博客所有C++代码都在Visual Studio 2022环境下编译运行。程序为64位。
目录
类模板的作用是建立一个通用类,类中的成员和数据类型可以不具体制定,用一个虚拟的类型代表。类模板的语法是:
template
类
template声明创建模板,typename表明后面的符号是一种数据类型,可以用class代替。T是数据类型名,可以替换,通常为大写字母。
- #include
- #include
- using namespace std;
- template<class a,class b>
- class person
- {
- public:
- a name;
- b age;
- person(a name, b age) {
- this->name = name;
- this->age = age;
- }
-
- void show() {
- cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- };
-
- int main(void)
- {
- person
int > p("Jimena", 36); - p.show();
- return 0;
- }
person类使用了类模板,成员变量name的类型为a,age的类型为b。成员函数show输出信息。main函数创建了一个person类对象,并指明类型分别为string和int,随后调用show函数。程序的输出是:
The name is Jimena
The age is 36
类模板没有自动类型推导的使用方式,必须显示类型指定类型。类模板在模板参数列表中可以有默认参数。
- #include
- #include
- using namespace std;
- template<typename A,typename B = int>
- class person {
- public:
- A name;
- B age;
- person(A name, B age) {
- this->name = name;
- this->age = age;
- }
- void show() {
- cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- };
-
- int main(void)
- {
- person
int > p1("Kate", 18); - person
p2("Kevin", 21); - p1.show();
- p2.show();
- return 0;
- }
程序的类模板默认B为int类型,因此在创建类的同时,尖括号内可以省略B的类型,此时B为int类型。程序的输出是:
The name is Kate
The age is 18
The name is Kevin
The age is 21
普通类的成员函数一开始就可以创建,而类模板的成员函数在调用时才创建。
类模板实例的对象,可以向函数传参。传入方式有这三种:
指定传入的类型,这样直接显示对象的数据类型。
参数模板化,这样将对象的参数变为模板进行传递。
整个类模板化,这样将这个对象类型进行模板化再进行传递。
- #include
- #include
- using namespace std;
- template<typename a,typename b>
- class person
- {
- public:
- a name;
- b age;
- person(a name, b age) {
- this->name = name;
- this->age = age;
- }
-
- void show(void) {
- cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- };
- void test(person
int > &p) - {
- p.show();
- }
- int main(void)
- {
- person
int > p("Howard", 24); - test(p);
- return 0;
- }
程序用类模板创建了一个person类,在main函数中创建了一个对象p,并指明其成员类型。随后将p作为参数传递给test函数。test函数接受一个person类对象,同时在形参列表中指明了其成员类型。随后调用其show成员函数。
程序的输出是:
The name is Howard
The age is 24
- #include
- #include
- using namespace std;
- template<typename a, typename b>
- class person
- {
- public:
- a name;
- b age;
- person(a name, b age) {
- this->name = name;
- this->age = age;
- }
-
- void show(void) {
- cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- };
-
- template<typename a,typename b>
- {
- p.show();
- }
-
- int main(void)
- {
- person
int > p("Harvey", 17); - test(p);
- return 0;
- }
程序用类模板创建了一个person类,在main函数中创建了一个对象p,并指明其成员类型。随后将p作为参数传递给test函数。test函数使用了函数模板,将person类的两个成员变量类型指定为a和b,随后调用其show函数。
程序的输出是:
The name is Harvey
The age is 17
- #include
- #include
- using namespace std;
- template<typename a, typename b>
- class person
- {
- public:
- a name;
- b age;
- person(a name, b age) {
- this->name = name;
- this->age = age;
- }
-
- void show(void) {
- cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- };
-
- template<typename T>
- void test(T& p)
- {
- p.show();
- }
-
- int main(void)
- {
- person
int > p("Hilary", 28); - test(p);
- return 0;
- }
程序用类模板创建了一个person类,在main函数中创建了一个对象p,并指明其成员类型。随后将p作为参数传递给test函数。test函数使用了类模板,将参数类型指定为T,随后调用其show函数。
程序的输出是:
The name is Hilary
The age is 28
如果子类继承的父类是一个类模板,那么子类在声明的时候要指定父类中T的类型,如果不指定就无法给子类分配内存。如果想灵活指定父类中T的类型,子类也要设置为类模板。
- #include
- using namespace std;
- template<typename T>
- class father
- {
- public:
- T fatherthing;
- void showfather(void) {
- cout << fatherthing << endl;
- }
- };
-
- class son :public father<int>
- {
- public:
- int sonthing;
- void showson(void) {
- cout << sonthing << endl;
- }
- };
- int main(void)
- {
- son s;
- s.sonthing = 10;
- s.fatherthing = 15;
- s.showson();
- s.showfather();
- return 0;
- }
父类father使用了类模板,内含类型为T的成员变量fatherthing,和成员函数showfather,该成员函数输出fatherthing的值。子类son在继承父类时指明了T是int。son类本身有int类型成员变量sonthing,和成员函数showson,showson函数输出sonthing的值。
main函数创建了一个son类型对象s,并进行了测试。程序的输出是:
10
15
- #include
- using namespace std;
- template<typename T>
- class father
- {
- public:
- T fatherthing;
- void showfather(void) {
- cout << fatherthing << endl;
- }
- };
-
- template<typename T>
- class son :public father
- {
- public:
- T sonthing;
- void showson(void) {
- cout << sonthing << endl;
- }
- };
-
- int main(void)
- {
- son<double> s;
- s.sonthing = 7.15;
- s.fatherthing = 11.40;
- s.showson();
- s.showfather();
- return 0;
- }
父类father使用了类模板,内含类型为T的成员变量fatherthing,和成员函数showfather,该成员函数输出fatherthing的值。子类son也使用了类模板,son类本身有T类型成员变量sonthing,和成员函数showson,showson函数输出sonthing的值。
main函数创建了一个son类型变量,并指定T为double类型。程序的输出是:
7.15
11.4
类模板成员函数在类外实现时,需要加上模板参数列表。
- #include
- using namespace std;
- template<typename T1,typename T2>
- class person
- {
- public:
- T1 name;
- T2 age;
- person(T1 name, T2 age);
- void show(void);
- };
-
- template<typename T1,typename T2>
- person
::person(T1 name, T2 age) { - this->name = name;
- this->age = age;
- }
- template<typename T1, typename T2>
- void person
::show(void) { - cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
- int main(void)
- {
- person
int > p("Ida", 13); - p.show();
- return 0;
- }
程序创建了类person,并将构造函数和成员函数show的实现放在了类外。这两个函数在实现时也加入了函数模板。main函数创建了一个对象,并进行了测试。程序的输出是:
The name is Ida
The age is 13
类模板的成员函数在调用时创建,因此分文件编写时链接不到。
可以通过直接包含.cpp源文件解决,但是一般不包含源文件。而是将声明和实现写在同一个文件中,将后缀改为.hpp。(.hpp是约定俗成的名称,非强制)
- #pragma once
- #include
- #include
- using namespace std;
- template<typename T1, typename T2>
- class person
- {
- public:
- T1 name;
- T2 age;
- person(T1 name, T2 age);
- void show(void);
- };
- #include
- #include
- #include"person.h"
- using namespace std;
- template<typename T1, typename T2>
- person
::person(T1 name, T2 age) { - this->name = name;
- this->age = age;
- }
- template<typename T1, typename T2>
- void person
::show(void) { - cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
这是person.h和person.cpp的内容,构成了person类的完整内容。person类使用了类模板。
- #include
- #include
- #include"person.cpp"
- using namespace std;
- int main(void)
- {
- person
int > p("Ignacio", 37); - p.show();
- return 0;
- }
这是测试代码,直接包含了源文件。程序的输出是:
The name is Ignacio
The age is 37
- #pragma once
- #include
- #include
- using namespace std;
- template<typename T1, typename T2>
- class person
- {
- public:
- T1 name;
- T2 age;
- person(T1 name, T2 age);
- void show(void);
- };
-
- template<typename T1, typename T2>
- person
::person(T1 name, T2 age) { - this->name = name;
- this->age = age;
- }
- template<typename T1, typename T2>
- void person
::show(void) { - cout << "The name is " << name << endl;
- cout << "The age is " << age << endl;
- }
person.hpp文件包含了person类的全部内容。person类使用了类模板。
- #include
- #include
- #include"person.hpp"
- using namespace std;
- int main(void)
- {
- person
int > p("Ivan", 18); - p.show();
- return 0;
- }
这是测试代码,程序的输出是:
The name is Ivan
The age is 18
全局函数实现友元可以在类内实现,也可以在类外实现。
类内实现时直接在类内声明友元即可,类外实现时需要提前让编译器知道全局函数的存在。
- #include
- #include
- using namespace std;
- template<typename A,typename B>
- class person
- {
- friend void show(person *p) {
- cout << "The name is " << p->name << endl;
- cout << "The age is " << p->age << endl;
- }
- public:
- person(A name,B age) {
- this->name = name;
- this->age = age;
- }
- private:
- A name;
- B age;
- };
- int main(void)
- {
- person
int > p("Igor", 17); - show(&p);
- return 0;
- }
person类的友元函数show直接在person类内实现,前面加了friend表示是友元。main函数创建了一个person类对象,并使用show函数访问。程序的输出是:
The name is Igor
The age is 17
- #include
- #include
- using namespace std;
- template<typename A, typename B>
- class person;
-
- template<typename A, typename B>
- cout << "The name is " << p->name << endl;
- cout << "The age is " << p->age << endl;
- }
-
- template<typename A, typename B>
- class person
- {
- public:
- person(A name, B age) {
- this->name = name;
- this->age = age;
- }
- private:
- A name;
- B age;
- };
- int main(void)
- {
- person
int > p("Irma", 15); - show(&p);
- return 0;
- }
程序创建了person类,在person类内声明show函数是友元函数,声明时要加上空模板参数列表。程序的show函数在类外实现。main函数创建了一个person类对象,并调用show函数。
程序的输出是:
The name is Irma
The age is 15