没什么可看的,都是我不会记录一下
0. 关于为什么要用 new
创建变量 原因是分给程序的栈空间一般很小,8M
空间 ,当有很大的数组或者变量的时候,栈空间不足,但是堆空间很大,可以使用堆空间。
1. 成员初始化表中成员初始化列表格式 如下形式,Student(string name,int age)
参数初始化对象中的参数 1 2 3 4 5 6 7 8 9 10 11 class Student { public: Student(string name,int age):name(Name),age(Age) { } private: string Name; int Age; };
2. new
创建数组,要使用如下方式删除数组 delete []数组名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 uint64_t *arr = new uint64_t[10]; int i = 0; for (i = 0; i < 10; i++) { if (i == 0) { *arr = 5; } else { arr[i] =*(arr+(i-1))*10; } } for (i = 0; i < 10; i++) { cout << *(arr + i) << endl; } delete[]arr; cout << "结束任务" << endl;
3. 对象的赋值和复制 (1)对象的赋值 如果两个对象都已存在,这种叫赋值
1 2 3 Student t1("pxl",29); Student t2("yuyu",56); t1 = t2;
(2)对象的复制(拷贝)用一个已存在的对象去创建一个新的对象,叫拷贝
1 2 Student t1("pxl",29); Student t2(t1);//Student t2 = t1;调用了一个拷贝构造函数
4. 如果一个函数返回的是一个类类型的对象,那么一定会调用拷贝构造函数 (这个过程,有些编译器会被优化,如果不希望被优先,可以加一个选项)-fno-elide-constructors
5. 拷贝构造函数(copy constructor) 当一个类中没有显式的去声明拷贝构造函数时候,编译器会自动生成。自动生成的拷贝构造函数执行:逐成员赋值
6. 不可重载运算符以及只能被成员函数重载运算符 1 2 3 4 5 6 不可重载运算符 sizeof sizeof运算符 . 成员运算符 .* 成员指针运算符 :: 作用域解析运算符 ?: 条件运算符
1 2 3 4 5 6 只能被成员函数重载运算符 = 赋值运算符 () 函数调用运算符 [] 下标运算符 -> 通过指针访问成员的运算符
7. 访问修饰符 1 2 3 private 私有的 只能在类的内部访问,外界不能直接访问 public 公有的 在任意地方都可以访问 protected 保护的 只能在类的内部访问,外界不能直接访问,其子类可以访问
8.浅拷贝与深拷贝 浅拷贝:多个指针指向同一段内存 深拷贝:每个指针指向单独的内存
9. new
和delete
重载函数,编译器默认加上了 static
是静态成员,该关键字可以是类成员也可以是全局成员。
10. using 使用using 关键字可以改变基类成员在派生类中的访问权限 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class A { public: int m_a = 10; protected: int m_b = 20; private: int m_c = 30; }; class B:public A { public: using A::m_b; //把m_b的权限修改为共有的 protected: private: using A::m_a; //把m_a的权限修改为私有的 };
11. 如果要使用基类(父类)的构造函数 ,可以在派生类(子类)中指明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class A { public: int m_a = 10; A() { cout << "调用了A的构造函数1。" << endl; } A(int a,int b,int c):m_a(a),m_b(b),m_c(c) { cout << "调用了A的构造函数2。" << endl; } A(A &co_a) :m_a(co_a.m_a), m_b(co_a.m_b), m_c(co_a.m_c) { cout << "调用了A的构造函数3。" << endl; } ~A() { cout << "调用了A的析构函数。" << endl; } void showA(void) { cout << "m_a = " << m_a << " m_b = " << m_b << " m_c = " << m_c << endl; } protected: int m_b = 20; private: int m_c = 30; }; class B:public A { public: int m_d; B():m_d(0),A() { cout << "调用了B的构造函数。" << endl; } B(int a,int b,int c,int d):A(a,b,c),m_d(d) { cout << "调用了B的构造函数,并初始化A。" << endl; } ~B() { cout << "调用了B的析构函数。" << endl; } void showB(void) { cout << "m_d = " << m_d << endl; } protected: private: };
12. 名字屏蔽和类解析符(继承的类中与父类中有同名函数,可以加上类名和作用域,调用父类中同名函数;当存在继承关系时,基类的作用域嵌套在派生类的作用域中,如果成员在派生类的作用域已经找到,就不会在基类作用域中继续查找,如果没有找到,则继续在基类作用域中查找;派生类与基类成员不能构成重载也是这个原因) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 class A { public: int m_a = 10; A() { cout << "调用了A的构造函数1。" << endl; } A(int a,int b,int c):m_a(a),m_b(b),m_c(c) { cout << "调用了A的构造函数2。" << endl; } A(A &co_a) :m_a(co_a.m_a), m_b(co_a.m_b), m_c(co_a.m_c) { cout << "调用了A的构造函数3。" << endl; } ~A() { cout << "调用了A的析构函数。" << endl; } void showA(void) { cout << "m_a = " << m_a << " m_b = " << m_b << " m_c = " << m_c << endl; } void show(void) { cout << "m_a = " << m_a << " m_b = " << m_b << " m_c = " << m_c << endl; } protected: int m_b = 20; private: int m_c = 30; }; class B:public A { public: int m_d; B():m_d(0),A() { cout << "调用了B的构造函数1,并初始化A。" << endl; } B(int a,int b,int c,int d):A(a,b,c),m_d(d) { cout << "调用了B的构造函数2,并初始化A。" << endl; } ~B() { cout << "调用了B的析构函数。" << endl; } void showB(void) { cout << "m_d = " << m_d << endl; } void show(void) { cout << "m_d = " << m_d << endl; } protected: private: }; void main() { B b(10, 20, 30, 40); b.showA(); b.showB(); b.A::show(); //重点 b.show(); }
13. 虚函数关键字: virtual 类中如果有虚函数,那么会创建虚函数列表,虚函数列表保存着虚函数地址,正常类成员函数,是在链接中放入类中 类中的成员变量。如果存在菱形的虚继承,也会出现虚成员表保存类成员,出现虚基类 如果要使用基类对象析构派生类对象时,需要对基类析构函数使用虚函数
14. 基类中即使不需要析构函数也需要创建一个虚析构函数 在有继承关系的类中需要注意的点
15. 纯虚函数,如果基类中有纯虚函数,无法创建对象实例化,但是可以创建指针或引用;含有虚函数的类被称为抽象类,不饿能实例化对象,可以创建指针和引用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 virtual void func() = 0;//基类中定义,但是继承类中一定要实现,才能实例化, class A { public: int m_a = 10; A() { cout << "调用了A的构造函数1。" << endl; } A(int a,int b,int c):m_a(a),m_b(b),m_c(c) { cout << "调用了A的构造函数2。" << endl; } A(A &co_a) :m_a(co_a.m_a), m_b(co_a.m_b), m_c(co_a.m_c) { cout << "调用了A的构造函数3。" << endl; } virtual ~A() = 0 { cout << "调用了A的析构函数。" << endl; } virtual void showA(void) = 0//一定要有代码实现 { cout << "m_a = " << m_a << " m_b = " << m_b << " m_c = " << m_c << endl; } protected: int m_b = 20; private: int m_c = 30; };
16. dynamic_cast
运算符用指向基类的指针来生成派生类的指针。他不能回答“指针指向的是什么类的对象”问题,但能回答“是否可以安全的将对象地址赋给特定类型的指针”问题(只适用于包含虚函数的类) 派生类指针 = dynamic_cast<派生类类型*
>(基类指针) 可以正确生成,则返回具体之,否则返回 nullptr
;
17. typeid运算符和type_info类 typeid 用于获取数据类型的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // expre_typeid_Operator.cpp // compile with: /GR /EHsc #include <iostream> #include <typeinfo> class Base { public: virtual void vvfunc() {} }; class Derived : public Base {}; using namespace std; int main() { Derived* pd = new Derived; Base* pb = pd; cout << typeid( pb ).name() << endl; //prints "class Base *" cout << typeid( *pb ).name() << endl; //prints "class Derived" cout << typeid( pd ).name() << endl; //prints "class Derived *" cout << typeid( *pd ).name() << endl; //prints "class Derived" delete pd; }
1 2 3 4 class Base * class Derived class Derived * class Derived
18. 关于 auto
的一些用法 方法一:代替冗长复杂的变量声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... double func(int a,int b , char *c ,int d) { cout << "a = " << a <<" b = " << b <<" c = "<< c << " d = " << d << endl; return 1.0; } int main() { auto funcp = func; funcp(10,20,"小婷",40); }
19. 函数模板概念 在对一个数据进行交换时,可能重载很多数据的交换类型,每增加一种数据类型,就要增加一个重载函数,这样始终不是很好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void Swap(int &a , int &b) { int &temp = a; a = b; b = temp; } void Swap(double &a , double &b) { double &temp = a; a = b; b = temp; } void Swap(char &a , char &b) { char &temp = a; a = b; b = temp; }
函数模板是通用的函数描述,使用任意类型(泛型)来描述函数 编译的时候,编译器推导实参的数据类型,根据实参的数据类型和函数模板,生成该类型的函数定义。 生成函数定义的过程被称为实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 //template 模板 //typename 类型名称 //template<typename anytype>//模板样板 anytype:任意类型名字。可以自己随意定义 void Swap(anytype& a, anytype& b) { anytype temp = a; a = b; b = temp; } void Swap(int & a, double& b) //可以对函数模板进行重载(这里只是举例子) { double temp = a; a = b; b = temp; } int main() { int a = 10; int b = 20; Swap(a,b); cout << "a = " << a << " b = " << b << endl; }
如果不想让编译器自动推导,可以手工指定市场的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 //template 模板 //typename 类型名称 template<typename anytype>//模板样板 anytype:任意类型名字。可以自己随意定义 void Swap(anytype& a, anytype& b) { anytype temp = a; a = b; b = temp; } void Swap(int & a, double& b) //可以对函数模板进行重载(这里只是举例子) { double temp = a; a = b; b = temp; } int main() { string str_a = "小婷", str_b = "小明"; Swap<string>(str_a, str_b);//<>中强制指定类型 cout << "str_a = " << str_a << " str_b = " << str_b << endl; }
在C++98添加关键字typename之前,C++使用关键字class来创建模板;建议使用 typename
1 2 template<typename anytype>//模板样板 anytype:任意类型名字。可以自己随意定义 template<class anytype>
可以为类的成员函数创建模板,但是不能是虚函数和析构函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class template_class { public: template<typename T> template_class(T perem) { cout << "perem = " << perem << endl; } template<typename T> void show(T perem) { cout << "perem = " << perem << endl; } private: protected: }; void main() { template_class temp_class("小婷"); temp_class.show("小婷"); }
参数模板,必须明确数据类型,确保实参与函数模板能匹配上;函数模板多个变量时候,一定要保证T
是相同类型,否则无法匹配,还有一个特殊类,函数模板没有参数,必须明确类型,如果没有参数,只能显示的指定类型了;
1 2 3 4 5 6 7 8 9 10 template<typename anytype>//模板样板 anytype:任意类型名字。可以自己随意定义 void show() { cout << "shou函数" << endl; } void main() { show<int>(); }
使用函数模板时,推导的数据类型必须适应函数模板中的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class CGil { public: }; template<typename T> T add_vlaue(T a, T b) { return a + b; } int main()//这种就不适用函数模板中的代码 { CGil a, b; add_vlaue(a,b); }
使用函数模板,如果是自动类型推导,不会发生隐式类型转换,如果显示指定了函数模板的数据类型,可以发生隐式类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template<typename T> T add_vlaue(T a, T b) { return a + b; } int main() { int a = 10; char b = 20; int c= add_vlaue<int>(a,b); //显式制定了函数模板的数据类型,编译器就可以对实参惊醒隐式类型转换 cout << "a + b = " << c <<endl; }
函数模板可以被重载,可以有非通用数据类型的参数(T Multi_type(T a, T2 b, int c));支持多个通用数据类型的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template<typename T, typename T2> T Multi_type(T a, T2 b) { T temp = a + b; return temp; } template<typename T, typename T2> T Multi_type(T a, T2 b, int c) { T temp = a + b; return temp; } template<typename T, typename T2, typename T3, typename T4, typename T5> T Multi_type(T a, T2 b, T3 c, T4 d, T5 e) { T temp = a + b + c + d + e; return temp; } c = Multi_type((unsigned int)b, (unsigned char)f);
20. 函数模板的具体化 可以提供一个具体化的函数定义,当编译器找到与函数调用匹配的具体化定义时,将使用该定义,不再寻找模板;具体化(特丽化、特化)的语法;就是函数通用版本以外的一个特殊版本: 具体函数的返回值、函数名和形参列表与函数模板相同,但是对具体化函数来说,不管是函数的声明还是函数体中,都是具体的数据类型,没有通用的数据类型了,函数体中代码随意写,满足要求就可以 编译器推导实参数据类型匹配,会直接使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class CGil { public: int m_rank; CGil(int a):m_rank(a) { } void show(string str) { cout << str + '.' << "m_rank = " << m_rank << endl; } }; template<typename T> void Swap(T &a, T &b) { T temp = a; a = b; b = temp; cout << "void Swap(T &a, T &b)" << endl; } /*如下两种方法是一样的效果*/ //template<> void Swap<CGil>(CGil& g1, CGil& g2) template<> void Swap(CGil& g1, CGil& g2) { int temp = g1.m_rank; g1.m_rank = g2.m_rank; g2.m_rank = temp; cout << "template<> void Swap(CGil& g1, CGil& g2)" << endl; } int main() { int a = 10, b = 20; CGil g1(10),g2(20); Swap(a, b); cout << "a = " << a << " ,b = " << b << endl; cout << "------------------------------------" << endl; Swap(g1,g2); g1.show("g1"); g2.show("g2"); }
函数模板声明和定义都可以分开写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template<typename T> void Swap(T &a, T &b); /*如下两种方法是一样的效果*/ //template<> \ void Swap<CGil>(CGil& g1, CGil& g2); template<> void Swap(CGil& g1, CGil& g2); ... template<typename T> void Swap(T &a, T &b) { T temp = a; a = b; b = temp; cout << "void Swap(T &a, T &b)" << endl; } //template<> void Swap<CGil>(CGil& g1, CGil& g2) template<> void Swap(CGil& g1, CGil& g2) { int temp = g1.m_rank; g1.m_rank = g2.m_rank; g2.m_rank = temp; cout << "template<> void Swap(CGil& g1, CGil& g2)" << endl; }
对于给定的函数名,有普通函数、函数模板、具体化函数模板、重载函数 如果多种函数都可以匹配上,编译器使用规则 普通函数(重载函数) > 具体化函数模板 > 函数模板 如果希望使用函数模板,可以使用空模板参数强制使用函数模板
1 2 //空模板函数示例 Swap<>(1,2);//使用具体化函数模板示例
如果函数模板能产生更好的匹配,将优先于普通函数
21. 函数模板-函数模板份文件编写 函数模板只是函数的描述,没有实体(函数模板只是模型,并没有直接写入可执行文件中,有点宏定义特性) 《C++ P P》 函数模板一般放在头文件中 函数模板只是函数的描述,没有实体,创建函数模板的代码放在头文件中。 函数模板的具体化有实体,编译的原理和普通函数一样,所以,声明放在头文件,定义在源文件中
xxx.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ... class CGil { public: int m_rank; CGil(int a):m_rank(a) { } void show(string str) { cout << str + '.' << "m_rank = " << m_rank << endl; } }; //函数模板 template<typename T> void Swap(T& a, T& b) { T temp = a; a = b; b = temp; cout << "void Swap(T &a, T &b)" << endl; } //函数模板具体化 //template<> void Swap<CGil>(CGil& g1, CGil& g2); template<> void Swap(CGil& g1, CGil& g2); ...
xxx.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #Include "xxx.h" template<> void Swap(CGil& g1, CGil& g2) { int temp = g1.m_rank; g1.m_rank = g2.m_rank; g2.m_rank = temp; cout << "template<> void Swap(CGil& g1, CGil& g2)" << endl; } int main() { int a = 10, b = 20; CGil g1(10),g2(20); Swap(a, b); cout << "a = " << a << " ,b = " << b << endl; cout << "------------------------------------" << endl; Swap(g1,g2); g1.show("g1"); g2.show("g2"); }
普通函数和函数模板具体化,在头文件声明,源文件中定义,函数模板都在头文件中(其他函数模板形式无意义);
函数模板有多个类型,并且有返回值,无法确认返回类型示例代码 1 2 3 4 5 6 7 template<typename T , tyoename T2> auto func(T x,T2 y) -> decltype(x + y)//后面在形参x和y的作用域内,前面不在形成 x 和 y 的作用域内 { decltype(x+y) temp = x+y; return temp; }
22. 函数模板-函数模板高级(当函数模板中,有多个通用类型时候使用) decltype
关键字,在C++11中,decltype 操作符,用于查询表达式的的数据类型 语法 decltype(expression) var; expression:填写表达式 var:是变量decltype
分析表达式并得到他的类型,不会计算执行表达式。函数调用也是一种表达式,因此不必担心在使用 decltype 时执行了函数。decltype
返回值是数据类型,可以用它定义变量,后面直接写变量名就行了;如果表达式中有函数,不用担心会被调用执行 decltype 规则 (1)如果 expression
是没有用括号括起来的标识符(decltype本身括号不算括号,要在decltype内部再加一个括号),则var的类型与该标识符的类型相同,包括const等限定符。
示例代码 1 2 3 4 5 6 int main() { short a = 5; decltype(a) da;//`da`变量类型与变量`a`相同,`a` `da`都是short }
(2)如果 expression
是函数调用,则var的类型与函数的返回值类型相同(函数不能返回 void
,但可以返回(void *)
;这是因为 void
无法声明变量)
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int func_main() { cout << "func_main 被调用" << endl; return 10; } int main() { int a = 100; //如下两个格式变量不相同 decltype表达式中,填函数调用和填函数名是两回事, //只填写函数名,得到的是函数的类型,不是返回值的类型 //函数返回值类型 decltype(func_main())func_main_value = a; decltype(func_main) func_main_value_g; //无用 void 无法声明变量 //函数名类型 :int()(),对变量名加入 * 号,转换为函数指针 decltype(func_main) *pfunc_main_value = func; // void * 声明变量 pfunc_main_value_g(); }
(3)如果 expression
是左值(能取地址)(排除第一种可能)、或者用括号括起来的标识符,那么var的类型是expression
的引用 示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int func_main() { cout << "func_main 被调用" << endl; return 10; } int main() { int b = 10; //注意:没有用括号和用了括号不一样 decltype(b) copy_b; //int copy_b; //加了括号都变成了引用 decltype((b)) yingyong1_b = b; // int &yingyong1_b = b; decltype((func_main)) yingyong_func_main = func_main;// int (&yingyong_func_main)() = func_main; //引用一定要初始化 yingyong_func_main(); }
(4)如果上面的条件都不满足,则var的类型与 expression
的类型相同; 示例代码 decltype:关键字不是应用就是,就是变量 如果需要多次使用decltype,可以结合 typedef
和 using
示例代码 1 2 3 4 using std::cout; //释放某个变量到当前作用域 using namespace std; //释放这个命名空间到当前作用域
函数后置返回值
1 2 3 int func(int x ,int y); //等同 auto func(int x,int y) -> int;//C++11中有的,不管是函数声明还是定义都可以这么写
将返回类型移到了函数声明后面。auto
是一个占位符(c++11给 auto
新增的角色),为函数返回值占了一个位置。 这种语法也可以用户函数定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 //函数模板有多个类型,并且有返回值,无法确认返回类型示例代码 template<typename T , tyoename T2> auto func(T x,T2 y) -> decltype(x + y)//后面在形参x和y的作用域内,前面不在形成 x 和 y 的作用域内 { decltype(x+y) temp = x+y; return temp; } auto func_main_3(int x,int y) -> int { cout << "func_main_2" << endl; return x + y; } auto func_main_2(int x, int y) -> decltype(x+y) { cout << "func_main_2" << endl; return x + y; } int main() { int b = func_main_2(100,100); }
C++14的 auto
关键字:C++14标准对函数返回类型推导规则做了优化,函数的返回值可以用 auto
,不必尾随返回类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 //函数模板有多个类型,并且有返回值,无法确认返回类型示例代码 template<typename T , typename T2> auto func(T x,T2 y) { decltype(x+y) temp = x+y; return temp; } auto func_main_3(int x,int y) { cout << "func_main_2" << endl; return x + y; } auto func_main_2(int x, int y) { cout << "func_main_2" << endl; return x + y; } int main() { int b = func_main_2(100,100); }
23. 类模板-模板类的基本概念 类模板与模板类都是同一个;函数模板和模板函数都是同一个。 类模板是通用类的描述,使用任意类型(泛型)来描述类的定义。 使用类模板的时候,指定具体的数据类型,让编译器生成该类型的类定义
语法 1 2 3 4 5 template<class T> class 类模板名 { 类的定义; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> using namespace std; template<class T, class T2> class AA { public: T m_a; //通用类型用于成员变量 T2 m_b; //通用类型用于成员变量 public: AA() { } //通用类型用于成员函数的参数 AA(T x, T2 y):m_a(x),m_b(y)// { } ~AA() { } //通用类型用于成员函数的返回值 T geta() { T a = 2; //通用类型用于成员函数的代码中 return m_a + a; } T2 getb() { T2 b = 2; return m_b + b; } private: }; int main() { AA <int, double > a;//类模板需要指定具体类型 a.m_a = 10; a.m_b = 10.5; cout << "a.m_a = " << a.m_a << endl; cout << "a.m_b = " << a.m_b << endl; cout << "a.geta() = " << a.geta() << endl; cout << "a.getb() = " << a.getb() << endl; }
使用类模板,数据类型必须适应类模板中的代码; 类模板可以为通用类型指定缺省值的数据类型(C++11标准的才支持函数模板缺省值设置,以前不可以)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 template<class T, class T2 = double> //如果T2没有指定类型,那么就会使用缺省值double class AA { public: T m_a; //通用类型用于成员变量 T2 m_b; //通用类型用于成员变量 public: AA() { } //通用类型用于成员函数的参数 AA(T x, T2 y):m_a(x),m_b(y)// { } ~AA() { } //通用类型用于成员函数的返回值 T geta() { T a = 2; //通用类型用于成员函数的代码中 return m_a + a; } T2 getb() { T2 b = 2; return m_b + b; } private: }; int main() { AA <int> a;//类模板需要指定具体类型 a.m_a = 10; a.m_b = 10.5; cout << "a.geta() = " << a.geta() << endl; cout << "a.getb() = " << a.getb() << endl; }
模板类的成员函数可以在类外实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 template<class T, class T2 = double> class AA { public: T m_a; //通用类型用于成员变量 T2 m_b; //通用类型用于成员变量 public: AA() { } //通用类型用于成员函数的参数 AA(T x, T2 y):m_a(x),m_b(y)// { } ~AA() { } //通用类型用于成员函数的返回值 T geta() { T a = 2; //通用类型用于成员函数的代码中 return m_a + a; } T2 getb(); private: }; template<class T, class T2> T2 AA<T, T2>::getb() { T2 b = 1; return m_b + b; } int main() { AA <int> a;//类模板需要指定具体类型 a.m_a = 10; a.m_b = 10.5; cout << "a.geta() = " << a.geta() << endl; cout << "a.getb() = " << a.getb() << endl; }
可以用new
创建模板类对象。
1 2 3 4 5 AA<int ,double> * p_a1 = new AA<int ,double>; AA<int, double>* p_a2 = new AA<int, double>(10, 10.5); delete p_a1; delete p_a2;
模板类的成员函数和模板函数相同,都是使用了才会创建,不使用不会创建。
24.模板类的示例-栈 模板类最常用的就是作为容器类 C++标准库:栈、数组、链表、二叉树和哈希表
25.模板类的示例-数组 定长数组:array容器(C++11标准) 可变数组:vector容器 类模板的非通用类型参数
定长数组:array容器(C++11标准) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> using namespace std; template<class T> class Array { public: T items[MAXLEN]; //数组元素 const T& operator[](int idenx) const; //重载操作符[], 可以修改数组中的元素 T& operator[](int idenx); //重载操作符[], 可以修改数组中的元素 public: Array(); ~Array(); private: protected: }; template<class T> Array<T>::Array() { memset(this->items,0,sizeof(this->items)); } template<class T> Array<T>::~Array() { } template<class T> const T &Array<T>::operator[](int index) const {//这里是不完善的,可以自己完善 return this->items[index]; } template<class T> T &Array<T>::operator[](int index) {//这里是不完善的,可以自己完善 return this->items[index]; } int main() { Array<int> array; array[3] = 10; cout << array[3] << endl; }
类模板的非通用类型参数;非通用类型参数可以有缺省值,创建类型的时候,可以不用填写
类模板的非通用类型参数(定长类数组容器) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 #include <iostream> using namespace std; template<class T,int len>//类模板可以支持非通用类 //template<class T,int len = 10>//类模板可以支持非通用类,非通用类添加缺省值 class Array { public: T items[len]; //数组元素 const T& operator[](int idenx) const; //重载操作符[], 可以修改数组中的元素 T& operator[](int idenx); //重载操作符[], 可以修改数组中的元素 public: Array(); ~Array(); private: protected: }; template<class T, int len> Array<T,len>::Array() { //memset(this->items,0,sizeof(this->items)); } template<class T, int len> Array<T,len>::~Array() { } template<class T, int len> const T &Array<T,len>::operator[](int index) const { return this->items[index]; } template<class T, int len> T &Array<T,len>::operator[](int index) { return this->items[index]; } int main() { //如下是三个类 Array<string,100> array; Array<string,101> array1; Array<string,102> array2; array[0] = "小0"; array[1] = "小1"; array[2] = "小2"; array[3] = "小3"; array[4] = "小4"; array[5] = "小5"; array[6] = "小6"; array[7] = "小7"; array[8] = "小8"; array[9] = "小9"; array[10] = "小10"; array[11] = "小11"; array[12] = "小12"; for (int i = 0; i < 13; i++) { cout << array[i].c_str() << endl; } }
类模板可以有非通用类型参数:1.通常是整型(C++20标准可以用其它);2.实例化模板必须用常量表达式;3.模板中不能修改参数的值 优点:在栈上分配内存,以维护,执行速度快,合适小型数组 缺点:在程序中,不同的非通用类型参数将导致编译器生成不同的类,导致程序的二进制代码会更大,运行的时候,占用的内存空间也更多,Vector_Array容器效率虽然不如Array容器,但是更通用,还可以自动扩展,也不会存在Array容器创建多个类定义的情况. 构造函数的方法更通用,因为数据的大小是类的成员(而不是硬编码),可以创建数组大小可变的类。
变长数组容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 #include <iostream> using namespace std; //------------------- template<class T>//类模板可以支持非通用类 class Vector_Array { public: int len; T* items; //数组元素 public: Vector_Array(int size = 10); ~Vector_Array(); void resize(int size);//扩展数组内存空间 int size_Array(void) const;//数组长度 const T& operator[](int idenx) const; //重载操作符[], 可以修改数组中的元素 T& operator[](int idenx); //重载操作符[], 可以修改数组中的元素 /*重载下表操作夫的函数也需要修改,需要加自动扩展数组功能, 如果访问数组的下标超出了数组长度,就扩展数组 注意:扩展数组参数可以调整,如果每次只扩展一位数据,就会频繁操作分配和释放内存, 可以一次扩展多个。*/ private: protected: }; template<class T> Vector_Array<T>::Vector_Array(int size) :len(size) { //memset(this->items,0,sizeof(this->items)); this->items = new T[this->len]; } template<class T> Vector_Array<T>::~Vector_Array() { delete[] this->items; this->items = nullptr; } template<class T> void Vector_Array<T>::resize(int size)//扩展数组内存空间 { T* temp = nullptr; int i = 0; if (size <= this->len) { return; } else { temp = new T[size]; for (i = 0; i < this->len; i++) { temp[i] = this->items[i]; } delete[] this->items; this->items = temp; this->len = size; } } template<class T> int Vector_Array<T>::size_Array(void) const { return this->len; } template<class T> const T& Vector_Array<T>::operator[](int index) const { return this->items[index]; } template<class T> T& Vector_Array<T>::operator[](int index) { if (index >= this->len) { this->resize(index + 10);//扩展数组长度 } else { } return this->items[index]; } int main() { Vector_Array<string>array(5); array[0] = "小11"; array[1] = "小12"; array[2] = "小13"; array[3] = "小14"; array[4] = "小15"; array[5] = "小16"; array[6] = "小17"; array[7] = "小18"; array[8] = "小19"; array[9] = "小110"; array[10] ="小111"; array[11] ="小112"; array[12] ="小113"; cout << "array.size_Array() = " << array.size_Array() << endl; for (int i = 0; i < array.size_Array(); i++) { cout << "array[" << i << "] = " << array[i] << endl; } }
26.类模板-嵌套和递归使用模板类 1.容器中有容器 2.数组的元素可以是栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 #include <iostream> using namespace std; template<class DataType> class Stack { public: DataType *items; int top; int stacksize; public: Stack(int size = 3); ~Stack(); bool isempty(); //判断栈是否为空。 bool isfull(); //判断栈是否以满 bool push(const DataType&item);//元素入栈 bool pop(DataType &item);//元素出栈 Stack &operator=(const Stack &v); private: protected: }; template<class DataType> Stack<DataType>::Stack(int size):stacksize(size) { this->top = 0; this->items = new DataType[size]; } template<class DataType> Stack<DataType>::~Stack() { delete[]this->items; this->items = nullptr; } template<class DataType> bool Stack<DataType>::isempty() //判断栈是否为空。 { return (this->top == 0); } template<class DataType> bool Stack<DataType>::isfull() //判断栈是否以满 { return (this->top == this->stacksize); } template<class DataType> bool Stack<DataType>::push(const DataType&item)//元素入栈 { if (this->top < this->stacksize) { this->items[this->top++] = item; return true; } return false; } template<class DataType> bool Stack<DataType>::pop(DataType &item)//元素出栈 { if (this->top > 0) { item = this->items[--this->top]; return true; } return false; } template<class DataType> Stack<DataType> &Stack<DataType>::operator=(const Stack &v) { delete[]this->items; //释放原内存 this->stacksize = v.stacksize; //栈实际的大小 this->items = new DataType[v.stacksize];//重新分配数组 for (int ii = 0; ii < this->stacksize; ii++)//复制数组中的元素 { this->items[ii] = v.items[ii]; } this->top = v.top;//栈顶指针 return *this; } //------------------- template<class T>//类模板可以支持非通用类 class Vector_Array { public: int len; T* items; //数组元素 public: Vector_Array(int size = 2); ~Vector_Array(); void resize(int size);//扩展数组内存空间 int size_Array(void) const;//数组长度 const T& operator[](int idenx) const; //重载操作符[], 可以修改数组中的元素 T& operator[](int idenx); //重载操作符[], 可以修改数组中的元素 /*重载下表操作夫的函数也需要修改,需要加自动扩展数组功能, 如果访问数组的下标超出了数组长度,就扩展数组 注意:扩展数组参数可以调整,如果每次只扩展一位数据,就会频繁操作分配和释放内存, 可以一次扩展多个。*/ Vector_Array & operator=(const Vector_Array & v);//重载复制运算符函数 private: protected: }; template<class T> Vector_Array<T>::Vector_Array(int size) :len(size) { //memset(this->items,0,sizeof(this->items)); this->items = new T[this->len]; } template<class T> Vector_Array<T>::~Vector_Array() { delete[] this->items; this->items = nullptr; } template<class T> void Vector_Array<T>::resize(int size)//扩展数组内存空间 { T* temp = nullptr; int i = 0; if (size <= this->len) { return; } else { temp = new T[size]; for (i = 0; i < this->len; i++) { temp[i] = this->items[i]; } delete[] this->items; this->items = temp; this->len = size; } } template<class T> int Vector_Array<T>::size_Array(void) const { return this->len; } template<class T> const T& Vector_Array<T>::operator[](int index) const { return this->items[index]; } template<class T> T& Vector_Array<T>::operator[](int index) { if (index >= this->len) { this->resize(index + 10);//扩展数组长度 } else { } return this->items[index]; } template<class T> Vector_Array<T> & Vector_Array<T>::operator=(const Vector_Array & v)//重载复制运算符函数 { delete[]this->items; this->len = v.len; this->items = new T[this->len]; for (int ii = 0; ii < this->len; ii++) { this->items[ii] = v.items[ii]; } return *this; } int main() { //Vector_Array容器的大小缺省值是2,Stack容器的大小缺省值是3 Vector_Array< Stack<string> > vs; //创建Vector_Array容器,容器中的元素用Stack //手工的往容器中插入数据 vs[0].push("小婷0"); //vs容器中的第0个栈 vs[0].push("小明0"); //vs容器中的第0个栈 vs[0].push("小雯0"); //vs容器中的第0个栈 vs[1].push("小婷1"); //vs容器中的第1个栈 vs[1].push("小明1"); //vs容器中的第1个栈 vs[1].push("小雯1"); //vs容器中的第1个栈 vs[2].push("小婷2"); //vs容器中的第2个栈 vs[2].push("小明2"); //vs容器中的第2个栈 vs[2].push("小雯2"); //vs容器中的第2个栈 vs[3].push("小婷3"); //vs容器中的第3个栈 vs[3].push("小明3"); //vs容器中的第3个栈 vs[3].push("小雯3"); //vs容器中的第3个栈 vs[4].push("小婷4"); //vs容器中的第4个栈 vs[4].push("小明4"); //vs容器中的第4个栈 vs[4].push("小雯4"); //vs容器中的第4个栈 vs[5].push("小婷5"); //vs容器中的第5个栈 vs[5].push("小明5"); //vs容器中的第5个栈 vs[5].push("小雯5"); //vs容器中的第5个栈 //用嵌套的循环,把容器中的数据显示出来 for (int ii = 0; ii < vs.size_Array(); ii++)//遍历Vector_Array容器 { while(!vs[ii].isempty())//遍历Stack容器 { string item; vs[ii].pop(item); cout << "item = " << item.c_str() << endl; } } }
3.栈中的元素可以是数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 #include <iostream> using namespace std; template<class DataType> class Stack { public: DataType *items; int top; int stacksize; public: Stack(int size = 3); ~Stack(); bool isempty(); //判断栈是否为空。 bool isfull(); //判断栈是否以满 bool push(const DataType&item);//元素入栈 bool pop(DataType &item);//元素出栈 Stack &operator=(const Stack &v); private: protected: }; template<class DataType> Stack<DataType>::Stack(int size):stacksize(size) { this->top = 0; this->items = new DataType[size]; } template<class DataType> Stack<DataType>::~Stack() { delete[]this->items; this->items = nullptr; } template<class DataType> bool Stack<DataType>::isempty() //判断栈是否为空。 { return (this->top == 0); } template<class DataType> bool Stack<DataType>::isfull() //判断栈是否以满 { return (this->top == this->stacksize); } template<class DataType> bool Stack<DataType>::push(const DataType&item)//元素入栈 { if (this->top < this->stacksize) { this->items[this->top++] = item; return true; } return false; } template<class DataType> bool Stack<DataType>::pop(DataType &item)//元素出栈 { if (this->top > 0) { item = this->items[--this->top]; return true; } return false; } template<class DataType> Stack<DataType> &Stack<DataType>::operator=(const Stack &v) { delete[]this->items; //释放原内存 this->stacksize = v.stacksize; //栈实际的大小 this->items = new DataType[v.stacksize];//重新分配数组 for (int ii = 0; ii < this->stacksize; ii++)//复制数组中的元素 { this->items[ii] = v.items[ii]; } this->top = v.top;//栈顶指针 return *this; } //------------------- template<class T>//类模板可以支持非通用类 class Vector_Array { public: int len; T* items; //数组元素 public: Vector_Array(int size = 2); ~Vector_Array(); void resize(int size);//扩展数组内存空间 int size_Array(void) const;//数组长度 const T& operator[](int idenx) const; //重载操作符[], 可以修改数组中的元素 T& operator[](int idenx); //重载操作符[], 可以修改数组中的元素 /*重载下表操作夫的函数也需要修改,需要加自动扩展数组功能, 如果访问数组的下标超出了数组长度,就扩展数组 注意:扩展数组参数可以调整,如果每次只扩展一位数据,就会频繁操作分配和释放内存, 可以一次扩展多个。*/ Vector_Array & operator=(const Vector_Array & v);//重载复制运算符函数 private: protected: }; template<class T> Vector_Array<T>::Vector_Array(int size) :len(size) { //memset(this->items,0,sizeof(this->items)); this->items = new T[this->len]; } template<class T> Vector_Array<T>::~Vector_Array() { delete[] this->items; this->items = nullptr; } template<class T> void Vector_Array<T>::resize(int size)//扩展数组内存空间 { T* temp = nullptr; int i = 0; if (size <= this->len) { return; } else { temp = new T[size]; for (i = 0; i < this->len; i++) { temp[i] = this->items[i]; } delete[] this->items; this->items = temp; this->len = size; } } template<class T> int Vector_Array<T>::size_Array(void) const { return this->len; } template<class T> const T& Vector_Array<T>::operator[](int index) const { return this->items[index]; } template<class T> T& Vector_Array<T>::operator[](int index) { if (index >= this->len) { this->resize(index + 2);//扩展数组长度 } else { } return this->items[index]; } template<class T> Vector_Array<T> & Vector_Array<T>::operator=(const Vector_Array & v)//重载复制运算符函数 { delete[]this->items; this->len = v.len; this->items = new T[this->len]; for (int ii = 0; ii < this->len; ii++) { this->items[ii] = v.items[ii]; } return *this; } int main() { //Vector_Array容器的大小缺省值是2,Stack容器的大小缺省值是3 Vector_Array< Stack<string> > vs;//数组中有栈 //创建Vector_Array容器,容器中的元素用Stack //手工的往容器中插入数据 vs[0].push("小婷0"); //vs容器中的第0个栈 vs[0].push("小明0"); //vs容器中的第0个栈 vs[0].push("小雯0"); //vs容器中的第0个栈 vs[1].push("小婷1"); //vs容器中的第1个栈 vs[1].push("小明1"); //vs容器中的第1个栈 vs[1].push("小雯1"); //vs容器中的第1个栈 vs[2].push("小婷2"); //vs容器中的第2个栈 vs[2].push("小明2"); //vs容器中的第2个栈 vs[2].push("小雯2"); //vs容器中的第2个栈 vs[3].push("小婷3"); //vs容器中的第3个栈 vs[3].push("小明3"); //vs容器中的第3个栈 vs[3].push("小雯3"); //vs容器中的第3个栈 vs[4].push("小婷4"); //vs容器中的第4个栈 vs[4].push("小明4"); //vs容器中的第4个栈 vs[4].push("小雯4"); //vs容器中的第4个栈 vs[5].push("小婷5"); //vs容器中的第5个栈 vs[5].push("小明5"); //vs容器中的第5个栈 vs[5].push("小雯5"); //vs容器中的第5个栈 //用嵌套的循环,把容器中的数据显示出来 for (int ii = 0; ii < vs.size_Array(); ii++)//遍历Vector_Array容器 { while(!vs[ii].isempty())//遍历Stack容器 { string item; vs[ii].pop(item); cout << "item = " << item.c_str() << endl; } } //创建Stack容器,容器中的元素用Vector_Array<string> Stack<Vector_Array<string>> sv;//栈中有数组 Vector_Array<string> temp; //栈的元素,临时Vector<string>容器 //第一个入栈的元素 temp[0] = "西施1"; temp[1] = "西施2"; sv.push(temp); //第二个入栈的元素 temp[0] = "西瓜1"; temp[1] = "西瓜2"; sv.push(temp); //第三个入栈的元素 temp[0] = "冰冰1"; temp[1] = "冰冰2"; temp[2] = "冰冰3"; temp[3] = "冰冰4"; sv.push(temp); Vector_Array<string> temp_pop; while (sv.isempty() == false) { sv.pop(temp_pop);//出栈一个元素,放在临时容器中 for (int ii = 0; ii < temp_pop.size_Array(); ii++)//遍历临时Vector_Array<string>容器,显示容器中每个元素的值 { cout << "vt[" << ii << "] = " << temp_pop[ii].c_str() << endl; } } //创建Vector_Array容器,容器中的元素用Vector_Array<string> Vector_Array<Vector_Array<string>> vv; //递归使用模板类 //char a[][]//二维指针,是连续内存 //char *a[] -> char b[]递归模板类 是先创建一个指针数组,指针数组元素再指向一个数组 //二维数组大小固定,这一个大小是可变的 vv[0][0] = "西施1"; vv[0][1] = "西施2"; vv[0][2] = "西施3"; vv[1][0] = "西瓜1"; vv[1][1] = "西瓜2"; vv[2][0] = "冰冰1"; vv[2][1] = "冰冰2"; vv[2][2] = "冰冰3"; vv[2][3] = "冰冰4"; for (int ii = 0; ii < vv.size_Array(); ii++) { for (int jj = 0; jj < vv[ii].size_Array(); jj++) { //cout << "vv[" << ii << "][" << jj << "]= " << vv[ii][jj].c_str() << endl; cout << vv[ii][jj].c_str() << " "; } cout << endl; } }
在 C++11 之前 嵌套使用模板类的时候 > >之间要加空格。
27.类模板-模板类具体化 模板类具体化(特化、特例化)有两种:完全具体化和部分具体化。
完全具体化:语法和函数模板集体化是相似的,template关键字,一对空的尖括号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 /*类模板*/ template<class T1, class T2> class AA { public: T1 m_x; T2 m_y; AA(const T1 x, const T2 y):m_x(x),m_y(y) { cout << "类模板:构造函数。" << endl; } void show() const; }; template<class T1, class T2> void AA<T1, T2>::show() const { cout << "类模板:x = " << this->m_x << " ,y = " << this->m_y << endl; } /*类模板完全具体化 模板类AA的一个完全具体化版本*/ template<> class AA<int, string> { public: int m_x; string m_y; AA(int x, string y) :m_x(x), m_y(y) { cout << "完全具体化:构造函数。" << endl; } void show()const; }; void AA<int,string>::show() const { cout << "完全具体化:x = " << this->m_x << " ,y = " << this->m_y.c_str() << endl; }
部分具体化:函数模板没有部分具体化说法,只有类模板才有, 部分具体化的意思是:为多个模板参数的部分参数指定具体的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 /*类模板*/ template<class T1, class T2> class AA { public: T1 m_x; T2 m_y; AA(T1 x, T2 y):m_x(x),m_y(y) { cout << "类模板:构造函数。" << endl; } void show() const; }; template<class T1, class T2> void AA<T1, T2>::show() const { cout << "类模板:x = " << this->m_x << " ,y = " << this->m_y << endl; } /*类模板部分具体化 模板类AA的一个部分具体化版本*/ template<class T1> class AA<T1, string> { public: T1 m_x; string m_y; AA(const T1 x, const string y) :m_x(x), m_y(y) { cout << "部分具体化:构造函数。" << endl; } void show()const; }; template<class T1> void AA<T1, string>::show() const { cout << "部分具体化:x = " << this->m_x << " ,y = " << this->m_y.c_str() << endl; }
调用示例 1 2 3 4 5 6 7 8 9 10 11 12 int main() { AA<int, string> aa_1(8, "完全具体化类模板"); aa_1.show(); AA<char, string> aa_2(8, "部分具体化类模板"); aa_2.show(); AA<char, int> aa_3(8, 8); aa_3.show(); }
使用模板规则:具体化程度高 > 集体化程度低 > 没有具体化的类;主要看匹配
28.类模板-模板类与继承 1)模板类继承普通类(常见)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include <iostream> using namespace std; class AA { public: AA(int a); ~AA(); void func1(); public: int m_a; private: }; AA::AA(int a):m_a(a) { cout << "调用了AA的构造函数\n"; } AA::~AA() { cout << "调用了AA析构函数\n"; } void AA::func1() { cout << "调用了func1()函数: m_a = " << this->m_a << endl; } template <class T1,class T2> class BB :public AA { public: T1 m_x; T2 m_y; public: BB(T1 x, T2 y, int a); ~BB(); void func2(); private: }; template <class T1, class T2> BB<T1,T2>::BB(T1 x,T2 y,int a):AA(a),m_x(x),m_y(y) { cout << "调用了BB构造函数\n"; } template <class T1, class T2> BB<T1, T2>::~BB() { cout << "调用了BB析构函数\n"; } template <class T1, class T2> void BB<T1, T2>::func2() { cout << "调用了func2()函数:x= " << this->m_x << " ,y=" << this->m_y.c_str() << endl; } int main() { BB<int, string> bb_1(8, "我是一只傻傻鸟", 9); bb_1.func2(); bb_1.func1(); }
2)普通类继承模板类的实例版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <iostream> using namespace std; template <class T1, class T2> class BB { public: T1 m_x; T2 m_y; public: BB(T1 x, T2 y); ~BB(); void func2(); private: }; template <class T1, class T2> BB<T1, T2>::BB(T1 x, T2 y) :m_x(x), m_y(y) { cout << "调用了BB构造函数\n"; } template <class T1, class T2> BB<T1, T2>::~BB() { cout << "调用了BB析构函数\n"; } template <class T1, class T2> void BB<T1, T2>::func2() { cout << "调用了func2()函数:x= " << this->m_x << " ,y=" << this->m_y.c_str() << endl; } class AA: public BB<int,string> { public: AA(int a, int x, string y); ~AA(); void func1(); public: int m_a; private: }; AA::AA(int a,int x,string y):m_a(a),BB(x,y) { cout << "调用了AA的构造函数\n"; } AA::~AA() { cout << "调用了AA析构函数\n"; } void AA::func1() { cout << "调用了func1()函数: m_a = " << this->m_a << endl; } int main() { //BB<int, string> bb_1(8, "我是一只傻傻鸟"); //bb_1.func2(); AA aa_1(1, 2, "我是一只傻傻鸟"); aa_1.func1(); aa_1.func2(); }
3)普通类继承模板类(常见) 要把普通类也变成模板类:注意的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <iostream> using namespace std; template <class T1, class T2> class BB { public: T1 m_x; T2 m_y; public: BB(T1 x, T2 y); ~BB(); void func2(); private: }; template <class T1, class T2> BB<T1, T2>::BB(T1 x, T2 y) :m_x(x), m_y(y) { cout << "调用了BB构造函数\n"; } template <class T1, class T2> BB<T1, T2>::~BB() { cout << "调用了BB析构函数\n"; } template <class T1, class T2> void BB<T1, T2>::func2() { cout << "调用了func2()函数:x= " << this->m_x << " ,y=" << this->m_y.c_str() << endl; } template <class T1, class T2> class AA: public BB<T1, T2> { public: AA(int a, const T1 x, const T2 y); ~AA(); void func1(); public: int m_a; private: }; template <class T1, class T2> AA<T1,T2>::AA(int a, const T1 x,const T2 y):m_a(a),BB<T1,T2>(x,y) { cout << "调用了AA的构造函数\n"; } template <class T1, class T2> AA<T1, T2>::~AA() { cout << "调用了AA析构函数\n"; } template <class T1, class T2> void AA<T1, T2>::func1() { cout << "调用了func1()函数: m_a = " << this->m_a << endl; } int main() { AA<int,string> aa_1(1, 2, "我是一只傻傻鸟"); aa_1.func1(); aa_1.func2(); }
4)模板类继承模板类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include <iostream> using namespace std; template <class T1, class T2> class BB { public: T1 m_x; T2 m_y; public: BB(T1 x, T2 y); ~BB(); void func2(); private: }; template <class T1, class T2> BB<T1, T2>::BB(T1 x, T2 y) :m_x(x), m_y(y) { cout << "调用了BB构造函数\n"; } template <class T1, class T2> BB<T1, T2>::~BB() { cout << "调用了BB析构函数\n"; } template <class T1, class T2> void BB<T1, T2>::func2() { cout << "调用了func2()函数:x= " << this->m_x << " ,y=" << this->m_y.c_str() << endl; } template <class T1, class T2> class AA: public BB<T1, T2> { public: AA(int a, const T1 x, const T2 y); ~AA(); void func1(); public: int m_a; private: }; template <class T1, class T2> AA<T1,T2>::AA(int a, const T1 x,const T2 y):m_a(a),BB<T1,T2>(x,y) { cout << "调用了AA的构造函数\n"; } template <class T1, class T2> AA<T1, T2>::~AA() { cout << "调用了AA析构函数\n"; } template <class T1, class T2> void AA<T1, T2>::func1() { cout << "调用了func1()函数: m_a = " << this->m_a << endl; } template<class T1,class T2,class T3> class CC : public BB<T2, T3> { public: T1 m_a; public: CC(T1 a, T2 x, T3 y); ~CC(); void func3(); private: }; template<class T1, class T2, class T3> CC<T1,T2 ,T3>::CC(T1 a,T2 x,T3 y):m_a(a), BB<T2,T3>(x,y) { cout << "调用了CC的构造函数\n"; } template<class T1, class T2, class T3> CC<T1, T2, T3>::~CC() { cout << "调用了CC析构函数\n"; } template<class T1, class T2, class T3> void CC<T1, T2, T3>::func3() { cout << "调用了func3()函数: m_a = " << this->m_a << endl; } int main() { CC<int ,int ,string> cc_1(4,5,"我是一只傻傻鸟"); cc_1.func2(); cc_1.func3(); }
5)模板类继承模板类参数给出的基类(不能是模板类)关注 EE
类 EE既是模板类,也是派生类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> using namespace std; class AA { public: AA() { cout << "调用了AA的构造函数AA()" << endl; } AA(int a) { cout << "调用了AA的构造函数AA(int a)" << endl; } ~AA() {}; }; class BB { public: BB() { cout << "调用了BB的构造函数BB()" << endl; } BB(int a) { cout << "调用了BB的构造函数BB(int a)" << endl; } ~BB() {}; }; class CC { public: CC() { cout << "调用了CC的构造函数CC()" << endl; } CC(int a) { cout << "调用了CC的构造函数CC(int a)" << endl; } ~CC() {}; }; template<class T> class DD { public: DD() { cout << "调用了DD的构造函数DD()" << endl; } DD(int a) { cout << "调用了DD的构造函数DD(T a)" << endl; } ~DD() {}; }; template<class T> class EE:public T //模板类继承模板阐述给出的基类 { public: EE():T() { cout << "调用了EE的构造函数EE()" << endl; } EE(int a):T(a) { cout << "调用了EE的构造函数EE(int a)" << endl; }//模板参数T调用基类构造函数 ~EE() {}; }; int main() { EE<AA> ea1; //AA作为基类 EE<BB> eb1; //BB作为基类 EE<CC> ec1; //CC作为基类 EE<DD<int>> ed1; //DD<int>作为基类 看上去像容器嵌套 }
EE继承模板T,也就是他继承的是可以改变的,
29.类模板-模板类与函数 模板类可以用于函数的参数和返回值,有三种形式 1)普通函数,参数和返回值是模板类的实例化版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> using namespace std; template<class T1,class T2> class AA //模板类AA { public: T1 m_x; T2 m_y; public: AA(const T1 x, const T2 y) :m_x(x), m_y(y) {} ~AA() {}; void show() const { cout << "show() x =" << m_x << " , y = " << m_y.c_str() << endl; } }; AA<int ,string> func(AA<int,string> &aa) { aa.show(); cout << "调用func(AA<int,string> &aa)函数" << endl; return aa; } int main() { AA<char, string> aa(3,"我是一只傻傻鸟"); func(aa); }
2)函数模板,参数和返回值是某种模板类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> using namespace std; template<class T1,class T2> class AA //模板类AA { public: T1 m_x; T2 m_y; public: AA(const T1 x, const T2 y) :m_x(x), m_y(y) {} ~AA() {}; void show() const { cout << "show() x =" << m_x << " , y = " << m_y.c_str() << endl; } }; //函数模板,参数和返回值的是模板类AA,这种不是通用的 template<typename T1,typename T2> AA<T1, T2> func(AA<T1, T2> &aa) { aa.show(); cout << "调用func(AA<T1, T2> &aa)函数" << endl; return aa; } int main() { AA<char, string> aa(3,"我是一只傻傻鸟"); func(aa); }
3)函数模板,参数和返回值是任意类型(支持普通类和米板类和其它类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> using namespace std; template<class T1,class T2> class AA //模板类AA { public: T1 m_x; T2 m_y; public: AA(const T1 x, const T2 y) :m_x(x), m_y(y) {} ~AA() {}; void show() const { cout << "show() x =" << m_x << " , y = " << m_y.c_str() << endl; } }; //函数模板类,参数和返回值都是任意类型 template<typename T1> T1 func(T1 &aa) { aa.show(); cout << "调用func(T1 &aa)函数" << endl; return aa; } int main() { AA<char, string> aa(3,"我是一只傻傻鸟"); func(aa); }
第三种方法更规范,支持所有的类或者普通函数,第二种方法只支持AA这一种模板类,函数模板不管传入什么,只要符合函数内部程序就可以