- 新增现代 C++ 教程的 Preface 章节,包括英文和中文版本 - 添加 C++ Primer 练习代码 - 新增 Learn C++ 教程的 C++ 开发简介章节 - 添加头文件解析文档 - 更新 mkdocs.yml,包含新教程的目录结构 - 修改项目设置,使用 Python 3.10环境
2102 lines
54 KiB
Plaintext
2102 lines
54 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# C++的模板"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 1. 模板简介"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① C++的一种编程思想称为泛型编程,主要利用的技术就是模板。\n",
|
||
"\n",
|
||
"② 模板就是建立通用的模具,大大提高复用性。\n",
|
||
"\n",
|
||
"③ 模板的特点:\n",
|
||
"\n",
|
||
"1. 模板不可以直接使用,它只是一个框架。\n",
|
||
"2. 模板的通用并不是万能的。\n",
|
||
"\n",
|
||
"④ C++提供两种模板机制:函数模板和类模板。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 2. 函数模板"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2.1 函数模板基本语法"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。\n",
|
||
"\n",
|
||
"② 函数模板利用关键字 template。\n",
|
||
"\n",
|
||
"③ 函数模板声明或定义为 template<typename T>\n",
|
||
"\n",
|
||
"1. template -- 声明创建模板\n",
|
||
"2. typename -- 表明其后面的符号是一种数据类型,可以用class代替\n",
|
||
"3. T -- 通用的数据类型,名称可以替换,通常为大写字母\n",
|
||
"\n",
|
||
"④ 使用函数模板有两种方式,自动类型推导、显示指定类型。\n",
|
||
"\n",
|
||
"⑤ 模板的目的是为了提高复用性,将类型也参数化。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//函数模板\n",
|
||
"\n",
|
||
"//两个整型交换函数\n",
|
||
"void swapInt(int& a, int& b)\n",
|
||
"{\n",
|
||
" int temp = a;\n",
|
||
" a = b;\n",
|
||
" b = temp;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//两个浮点型交换函数\n",
|
||
"void swapDouble(double &a, double &b)\n",
|
||
"{\n",
|
||
" double temp = a;\n",
|
||
" a = b;\n",
|
||
" b = temp;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//函数模板\n",
|
||
"template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型\n",
|
||
"void mySwap( T &a, T &b)\n",
|
||
"{\n",
|
||
" T temp = a;\n",
|
||
" a = b;\n",
|
||
" b = temp;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" int a = 10;\n",
|
||
" int b = 20;\n",
|
||
"\n",
|
||
" swapInt(a, b);\n",
|
||
" cout << \"a= \" << a << endl;\n",
|
||
" cout << \"b= \" << b << endl;\n",
|
||
"\n",
|
||
" double c = 1.1;\n",
|
||
" double d = 2.2;\n",
|
||
" swapDouble(c, d);\n",
|
||
" cout << \"c= \" << c << endl;\n",
|
||
" cout << \"d= \" << d << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" int m = 10;\n",
|
||
" int n = 20;\n",
|
||
" //利用函数模板交换\n",
|
||
" //两种方式使用函数模板\n",
|
||
" //1、自动类型推导\n",
|
||
" mySwap(m,n); //根据m、n的数据为int,自动设置为T为int\n",
|
||
" cout << \"m= \" << m << endl;\n",
|
||
" cout << \"n= \" << n << endl;\n",
|
||
"\n",
|
||
" //2、显示指定类型\n",
|
||
" mySwap<int>(m,n); //指定模板中数据类型T为int型\n",
|
||
" cout << \"m= \" << m << endl;\n",
|
||
" cout << \"n= \" << n << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- a= 20 \n",
|
||
"- b= 10 \n",
|
||
"- c= 2.2 \n",
|
||
"- d= 1.1 \n",
|
||
"- m= 20 \n",
|
||
"- n= 10 \n",
|
||
"- m= 10 \n",
|
||
"- n= 20 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2.2 函数模板注意事项"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 注意事项一:自动类型推导,必须推导出一致的数据T才可以使用。\n",
|
||
"\n",
|
||
"② 注意事项二:模板必须要确定T的数据类型,才可以使用。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//函数模板注意事项\n",
|
||
"\n",
|
||
"template<class T> //typename 可以替换成class\n",
|
||
"void mySwap(T&a,T&b)\n",
|
||
"{\n",
|
||
" T temp = a;\n",
|
||
" a = b;\n",
|
||
" b = temp;\n",
|
||
"}\n",
|
||
"//1、自动类型推导,必须推导出一致的数据类型T才可以使用\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" int a = 10;\n",
|
||
" int b = 20;\n",
|
||
" char c = 'c';\n",
|
||
"\n",
|
||
" mySwap(a, b); //正确\n",
|
||
" //mySwap(a, c); //错误,推导不出一致的T类型\n",
|
||
"\n",
|
||
" cout << \"a= \" << a << endl;\n",
|
||
" cout << \"b= \" << b << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//2、模板必须要确定出T的数据类型,才可以使用\n",
|
||
"template<class T>\n",
|
||
"void func()\n",
|
||
"{\n",
|
||
" cout << \"func 调用\" << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" //func(); //错误,模板必须要确定T的数据类型才可以使用\n",
|
||
" func<int>(); //正确,指定了模板的数据类型为int\n",
|
||
"}\n",
|
||
"\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- a= 20\n",
|
||
"- b= 10\n",
|
||
"- func 调用\n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2.3 普通函数与函数模板区别"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 普通函数调用时可以发生自动类型转换(隐式类型转换)。\n",
|
||
"\n",
|
||
"② 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换。\n",
|
||
"\n",
|
||
"③ 如果利用显示指定类型的方式,可以发生隐式类型转换。\n",
|
||
"\n",
|
||
"④ 建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//普通函数与函数模板区别\n",
|
||
"\n",
|
||
"//1、普通函数调用可以发生隐式类型转换\n",
|
||
"//2、函数模板 用自动类型推导,不可以发生隐式类型转换\n",
|
||
"//3、函数模板 用显示指定类型,可以发生隐式类型转换\n",
|
||
"\n",
|
||
"//普通函数\n",
|
||
"int myAdd01(int a, int b)\n",
|
||
"{\n",
|
||
" return a + b;\n",
|
||
"}\n",
|
||
"\n",
|
||
"template<class T>\n",
|
||
"T myAdd02(T a, T b)\n",
|
||
"{\n",
|
||
" return a + b;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" int a = 10;\n",
|
||
" int b = 20;\n",
|
||
" char c = 'c'; // ASCII码,a - 97,c - 99\n",
|
||
" cout << myAdd01(a, b) << endl;\n",
|
||
" cout << myAdd01(a, c) << endl; //进行了隐式转换,把 c 转换为整型\n",
|
||
"\n",
|
||
" //自动类型推导\n",
|
||
" //cout << myAdd02(a, c) << endl; //报错,编译器不知道把T转为整型还是字符型\n",
|
||
"\n",
|
||
" //显示指定类型\n",
|
||
" cout << myAdd02<int>(a, c) << endl; //明确告诉编译器T是int类型,不是int类型的,自动转换为int类型\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 30 \n",
|
||
"- 109 \n",
|
||
"- 109 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2.4 普通函数与函数模板调用规则"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 如果函数模板和普通函数都可以实现,优先调用普通函数。\n",
|
||
"\n",
|
||
"② 可以通过空模板参数列表来强制调用函数模板。\n",
|
||
"\n",
|
||
"③ 函数模板也可以发生重载。\n",
|
||
"\n",
|
||
"④ 如果函数模板可以产生更好的匹配,优先调用函数模板。\n",
|
||
"\n",
|
||
"⑤ 既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//普通函数与函数模板调用规则\n",
|
||
"\n",
|
||
"//1、如果函数模板和普通函数都可以实现,优先调用普通函数。\n",
|
||
"//2、可以通过空模板参数列表来强制调用函数模板。\n",
|
||
"//3、函数模板也可以发生重载。\n",
|
||
"//4、如果函数模板可以产生更好的匹配,优先调用函数模板。\n",
|
||
"\n",
|
||
"//普通函数\n",
|
||
"void myPrint(int a, int b)\n",
|
||
"{\n",
|
||
" cout << \"调用的普通函数\" << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//函数模板\n",
|
||
"template<class T>\n",
|
||
"void myPrint(T a, T b)\n",
|
||
"{\n",
|
||
" cout << \"调用的模板\" << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//函数模板重载\n",
|
||
"template<class T>\n",
|
||
"void myPrint(T a, T b,T c)\n",
|
||
"{\n",
|
||
" cout << \"调用重载的模板\" << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" int a = 10;\n",
|
||
" int b = 20;\n",
|
||
"\n",
|
||
" myPrint(a,b); //如果函数模板和普通函数都可以实现,优先调用普通函数。\n",
|
||
" //如果普通函数只有声明没有定义,即使有函数模板定义,会报错,也不会调用函数模板\n",
|
||
"\n",
|
||
" myPrint<>(a, b); //通过空模板参数列表,强制调用函数模板\n",
|
||
"\n",
|
||
" myPrint(a, b, 100); //三个参数,调用函数模板重载\n",
|
||
"\n",
|
||
" char c1 = 'a';\n",
|
||
" char c2 = 'b';\n",
|
||
" myPrint(c1, c2); //虽然它可以隐式的把char类型转为int,调用普通函数,但是编译器认为模板直接把T定义为char更方便,所以编译器认为函数模板比普通函数更匹配\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 调用的普通函数 \n",
|
||
"- 调用的模板 \n",
|
||
"- 调用重载的模板 \n",
|
||
"- 调用的模板 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 2.5 函数模板案例"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"案例描述: \n",
|
||
"1. 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序。\n",
|
||
"2. 排序规则从大到小、排序算法为选择排序。 \n",
|
||
"3. 分别利用char数组和int数组进行测试。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//实现通用 对数组进行排序的函数\n",
|
||
"//规则 从大到小\n",
|
||
"//算法 选择\n",
|
||
"//测试 char 数组、int 数组\n",
|
||
"\n",
|
||
"//交换函数模板\n",
|
||
"template<class T>\n",
|
||
"void mySwap(T& a, T& b)\n",
|
||
"{\n",
|
||
" T temp = a;\n",
|
||
" a = b;\n",
|
||
" b = temp;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//排序算法\n",
|
||
"template<class T>\n",
|
||
"void mySort(T arr[], int len) //数组类型不确定,但是数组的长度类型肯定为int型\n",
|
||
"{\n",
|
||
" for (int i = 0; i < len; i++)\n",
|
||
" {\n",
|
||
" int max = i; //认定最大值的下标\n",
|
||
" for (int j = i + 1; j < len; j++)\n",
|
||
" {\n",
|
||
" //认定的最大值 比 遍历出的数值 要小,说明j下标的元素才是真正的最大值\n",
|
||
" if (arr[max] < arr[j])\n",
|
||
" {\n",
|
||
" max = j;//更新最大值下标\n",
|
||
" }\n",
|
||
" }\n",
|
||
" if (max != i)\n",
|
||
" {\n",
|
||
" //交换max和i元素\n",
|
||
" mySwap(arr[max], arr[i]);\n",
|
||
" }\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"//提供打印数组模板\n",
|
||
"template<class T>\n",
|
||
"void printArray(T arr[], int len)\n",
|
||
"{\n",
|
||
" for (int i = 0; i < len; i++)\n",
|
||
" {\n",
|
||
" cout << arr[i] << \" \";\n",
|
||
" }\n",
|
||
" cout << endl;\n",
|
||
" }\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" //测试char数组\n",
|
||
" char charArr[] = \"badcfe\";\n",
|
||
" int num = sizeof(charArr) / sizeof(char);\n",
|
||
" mySort(charArr, num);\n",
|
||
" printArray(charArr, num);\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" //测试int数组\n",
|
||
" int intArr[] = { 7,5,1,3,9,2,4,6,8 };\n",
|
||
" int num = sizeof(intArr) / sizeof(int);\n",
|
||
" mySort(intArr, num);\n",
|
||
" printArray(intArr, num);\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- f e d c b a \n",
|
||
"- 9 8 7 6 5 4 3 2 1 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 3. 类模板"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.1 类模板基本语法"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板作用:建立一个通用类,类中的成员数据可以不具体制定,用一个虚拟的类型来代表。\n",
|
||
"\n",
|
||
"② 类模板语法如下所示。语法注释:\n",
|
||
"\n",
|
||
"1. template -- 声明创建模板\n",
|
||
"2. typename -- 表明后面的符号是一种数据类型,可以用class代替\n",
|
||
"3. T -- 通用的数据类型,名称可以替换,通常为大写字母\n",
|
||
"\n",
|
||
"③ 类模板和函数模板语法相似,在声明模板template后面加类,此类称为模板。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"// 语法: \n",
|
||
"\n",
|
||
"template<typename T> \n",
|
||
"类"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板\n",
|
||
"template<class NameType,class AgeType>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(NameType name, AgeType age) //构造函数赋初值\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
" void showPerson()\n",
|
||
" {\n",
|
||
" cout << \"name:\" << this->m_Name << \"age:\" << this->m_Age << endl;\n",
|
||
" }\n",
|
||
" NameType m_Name;\n",
|
||
" AgeType m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int> p1(\"孙悟空\", 999); //尖括号<>里面是模板的参数列表 \n",
|
||
" p1.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果:\n",
|
||
" - name:孙悟空age:999"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.2 类模板与函数模板区别"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板与函数模板区别主要有两点:\n",
|
||
"\n",
|
||
"1. 类模板没有自动类型推导的使用方式。\n",
|
||
"2. 类模板在模板参数列表中可以有默认参数。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板与函数模板区别\n",
|
||
"template<class NameType,class AgeType = int>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(NameType name, AgeType age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
" void showPerson()\n",
|
||
" {\n",
|
||
" cout << \"name:\" << this->m_Name << \"age=\" << this->m_Age << endl;\n",
|
||
" }\n",
|
||
"\n",
|
||
" NameType m_Name;\n",
|
||
" AgeType m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//1、类模板没有自动类型推导的使用方式。\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" //Person p(\"孙悟空\", 1000); //错误,无法用自动类型推导\n",
|
||
" Person<string,int> p(\"孙悟空\", 1000); //正确,只能用显示指定类型\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"//2. 类模板在模板参数列表中可以有默认参数。\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" Person<string> p(\"猪八戒\", 999); //正确,只能用显示指定类型\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- name:孙悟空age=1000 \n",
|
||
"- name:猪八戒age=999 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.3 类模板中成员函数创建时机"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板中成员函数和普通类中成员函数创建时机是有区别的。\n",
|
||
"\n",
|
||
"② 普通类中的成员函数一开始就可以创建。\n",
|
||
"\n",
|
||
"③ 类模板中的成员函数在调用时才创建。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板中成员函数创建时机\n",
|
||
"//类模板中成员函数在调用时才去创建\n",
|
||
"class Person1\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" void showPerson1() //普通类中的成员函数一开始就可以创建。\n",
|
||
" {\n",
|
||
" cout << \"Person1 show\" << endl; \n",
|
||
" }\n",
|
||
"};\n",
|
||
"\n",
|
||
"class Person2\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" void showPerson2()\n",
|
||
" {\n",
|
||
" cout << \"Person2 show\" << endl;\n",
|
||
" }\n",
|
||
"};\n",
|
||
"\n",
|
||
"template<class T>\n",
|
||
"class MyClass\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" T obj;\n",
|
||
"\n",
|
||
" //类模板中的成员函数\n",
|
||
" void func1() // 类模板中的成员函数在调用时才创建。\n",
|
||
" {\n",
|
||
" obj.showPerson1();\n",
|
||
" }\n",
|
||
"\n",
|
||
" void func2()\n",
|
||
" {\n",
|
||
" obj.showPerson2();\n",
|
||
" }\n",
|
||
"};\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" MyClass<Person1> m;\n",
|
||
" m.func1();\n",
|
||
" //m.func2(); // 报错,声明了模板是Person1类型,obj.showPerson2()是调用Person1类中的showPerson2()方法,然而Person1类中没有showPerson2()方法,所以会报错 \n",
|
||
" // 如果传入的是<Person2>,此方法就不会报错\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- Person1 show \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.4 类模板对象做函数参数"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板实例化出的对象,向函数传参的方式,一共有三种传入方式:\n",
|
||
"\n",
|
||
"1. 指定传入的类型 -- 直接显示对象的数据类型\n",
|
||
"2. 参数模板化 -- 将对象中的参数变为模板进行传递\n",
|
||
"3. 整个类模板化 -- 将这个对象类型 模板化进行传递\n",
|
||
"\n",
|
||
"② 使用比较广泛的是第一种:指定传入类型。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板对象做函数参数\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
" void showPerson()\n",
|
||
" {\n",
|
||
" cout << \"姓名:\" << this->m_Name << \" 年龄:\" << this->m_Age << endl;\n",
|
||
" }\n",
|
||
"\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"\n",
|
||
"//1、指定传入类型\n",
|
||
"void printPerson1(Person<string, int>& p)\n",
|
||
"{\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int> p(\"孙悟空\", 100);\n",
|
||
" printPerson1(p);\n",
|
||
"}\n",
|
||
"\n",
|
||
"//2、参数模板化\n",
|
||
"template<class T1,class T2>\n",
|
||
"void printPerson2(Person<T1, T2>& p)\n",
|
||
"{\n",
|
||
" p.showPerson();\n",
|
||
" cout << \"T1的类型为:\" << typeid(T1).name() << endl; //string的名字很长\n",
|
||
" cout << \"T2的类型为:\" << typeid(T2).name() << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" Person<string, int> p(\"猪八戒\", 90);\n",
|
||
" printPerson2(p);\n",
|
||
"}\n",
|
||
"\n",
|
||
"//3、整个类模板化\n",
|
||
"template<class T>\n",
|
||
"void printPerson3(T &p)\n",
|
||
"{\n",
|
||
" p.showPerson();\n",
|
||
" cout << \"T的类型为:\" << typeid(T).name() << endl; //打印出来为:class Person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int> \n",
|
||
" //会把整个类打印出来,类的类型为Person,里面有两个类型:basic_string型、int型,类似打印 Person<string, int> \n",
|
||
"}\n",
|
||
"\n",
|
||
"void test03()\n",
|
||
"{\n",
|
||
" Person<string, int> p(\"唐僧\", 30);\n",
|
||
" printPerson3(p);\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
" test03();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 姓名:孙悟空 年龄:100 \n",
|
||
"- 姓名:猪八戒 年龄:90 \n",
|
||
"- T1的类型为:class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > \n",
|
||
"- T2的类型为:int \n",
|
||
"- 姓名:唐僧 年龄:30 \n",
|
||
"- T的类型为:class Person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int> \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.5 类模板与继承"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型。\n",
|
||
"\n",
|
||
"② 如果不指定父类中T的类型,编译器无法给子类分配内存。\n",
|
||
"\n",
|
||
"③ 如果想灵活指定出父类中T的类型,子类也需要变为类模板。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"\n",
|
||
"//类模板与继承\n",
|
||
"template<class T>\n",
|
||
"class Base\n",
|
||
"{\n",
|
||
" T m;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//class Son :public Base // 报错,必须要知道父类中T类型,才能继承给子类,因为编译器不知道给子类多少个内存空间,如果T是int型给1个字节,但是T是double型给4个字节\n",
|
||
"class Son:public Base<int>\n",
|
||
"{\n",
|
||
"\n",
|
||
"};\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Son s1;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//如果想灵活指定父类中T类型,子类也需要变类模板\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Son2 :public Base<T2> //T2给了父类\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Son2()\n",
|
||
" {\n",
|
||
" cout << \"T1的类型为:\" << typeid(T1).name() << endl;\n",
|
||
" cout << \"T2的类型为:\" << typeid(T2).name() << endl;\n",
|
||
" }\n",
|
||
" T1 obj; //T1 给了子类\n",
|
||
"};\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" Son2 <int, char>S2; //T1为int,即obj为int型,T2为char型,即m为char型\n",
|
||
"\n",
|
||
"}\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- T1的类型为:int \n",
|
||
"- T2的类型为:char \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.6 类模板成员函数类外实现"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.6.1 类模板成员函数类外实现规则"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板成员函数类外实现时,需要加上模板参数列表。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.6.2 类模板成员函数类内实现"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板成员函数类内实现\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
" void showPerson()\n",
|
||
" {\n",
|
||
" cout << \"姓名:\" << this->m_Name << \" 年龄:\" << this->m_Age << endl;\n",
|
||
" }\n",
|
||
"\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string,int>s1(\"张三\",18);\n",
|
||
" s1.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 姓名:张三 年龄:18 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.6.3 类模板成员函数类外实现"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//类模板成员函数类内实现\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age); //构造函数声明\n",
|
||
"\n",
|
||
" void showPerson(); //函数声明\n",
|
||
"\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//构造函数类外实现\n",
|
||
"template<class T1,class T2>\n",
|
||
"Person<T1, T2>::Person(T1 name, T2 age) //Person<T1,T2>说明这是一个Person类模板的类外成员函数实现,Person::Person(T1 name, T2 age)表示类的函数的类外实现,Person(T1 name, T2 age)表示构造函数\n",
|
||
"{\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//成员函数类外实现\n",
|
||
"template<class T1,class T2>\n",
|
||
"void Person<T1, T2>::showPerson() // 有<T1, T2>表示是类模板的成员函数类外实现,Person表示是Person作用域的showPerson函数 \n",
|
||
"{\n",
|
||
" cout << \"姓名:\" << this->m_Name << \" 年龄:\" << this->m_Age <<endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string,int>s1(\"张三\",18);\n",
|
||
" s1.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 姓名:张三 年龄:18 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.7 类模板分文件编写"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.7.1 类模板分文件编写简介"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到。\n",
|
||
"\n",
|
||
"② 解决方式:\n",
|
||
"\n",
|
||
"1. 解决方式1:直接包含.cpp源文件。\n",
|
||
"2. 解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,.hpp是约定的名称,并不是强制。\n",
|
||
"\n",
|
||
"③ 主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.7.2 类模板没有分文件编写"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"// 类模板没有分文件编写时\n",
|
||
"\n",
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include <string>\n",
|
||
"//类模板分文件编写问题以及解决\n",
|
||
"\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age);\n",
|
||
"\n",
|
||
" void showPerson();\n",
|
||
"\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"template<class T1,class T2>\n",
|
||
"Person<T1, T2>::Person(T1 name, T2 age)\n",
|
||
"{\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
"}\n",
|
||
"\n",
|
||
"template<class T1, class T2>\n",
|
||
"void Person<T1,T2>::showPerson()\n",
|
||
"{\n",
|
||
" cout << \"姓名:\" << this->m_Name << \" 年龄:\" << this->m_Age << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int>p(\"Jerry\", 18);\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- 姓名:Jerry 年龄:18 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.7.3 类模板分文件编写(方式一)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.3.1 方式一简介"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 第一种解决方式,直接包含.cpp源文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.3.2 person.h 文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"//person.h 文件\n",
|
||
"#pragma once //表示防止头文件重复包含\n",
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include <string>\n",
|
||
"\n",
|
||
"template<class T1, class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age);\n",
|
||
"\n",
|
||
" void showPerson();\n",
|
||
"\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.3.3 person.cpp 文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include \"person.h\"\n",
|
||
"template<class T1, class T2>\n",
|
||
"Person<T1, T2>::Person(T1 name, T2 age)\n",
|
||
"{\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
"}\n",
|
||
"\n",
|
||
"template<class T1, class T2>\n",
|
||
"void Person<T1, T2>::showPerson()\n",
|
||
"{\n",
|
||
" cout << \"姓名:\" << this->m_Name << \"年龄:\" << this->m_Age << endl;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.3.4 main.cpp 文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"//第一种解决方式,直接包含源文件\n",
|
||
"#include \"person.cpp\" //不能使用 #include \"person.h\" \n",
|
||
" //person.h文件中包含的是类模板的成员函数,如果仅包含 #include \"person.h\",由于类模板中的成员函数并没有创建,编译器并不会去找 Person(T1 name, T2 name); void showPerson(); 这两个函数的定义,即编译器从来都没有见到过,所以导致test01()中运行Person<string, int>p(\"Jerry\", 18);和p.showPerson();会报错 \n",
|
||
" \n",
|
||
" //如果包含#include \"person.cpp\"就会看到 Person(T1 name, T2 name); void showPerson(); 这两个函数的定义,由于#include \"person.cpp\"上面有#include \"person.h\"就又回看到.h文件中的声明,因此.h与.cpp文件都看到了 \n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int>p(\"Jerry\", 18);\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.7.4 类模板分文件编写(方式二)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.4.1 方式二简介"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 第二种解决方式,将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.4.2 person.hpp文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"//person.hpp 文件\n",
|
||
"#pragma once //表示防止头文件重复包含\n",
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include <string>\n",
|
||
"\n",
|
||
"template<class T1, class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age);\n",
|
||
"\n",
|
||
" void showPerson();\n",
|
||
" \n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//构造函数 类外实现\n",
|
||
"template<class T1, class T2>\n",
|
||
"Person<T1, T2>::Person(T1 name, T2 age)\n",
|
||
"{\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//成员函数 类外实现\n",
|
||
"template<class T1, class T2>\n",
|
||
"void Person<T1, T2>::showPerson()\n",
|
||
"{\n",
|
||
" cout << \"姓名:\" << this->m_Name << \"年龄:\" << this->m_Age << endl;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### 3.7.4.3 main.cpp 文件"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include \"person.hpp\" \n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int>p(\"Jerry\", 18);\n",
|
||
" p.showPerson();\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.8 类模板与友元"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 全局函数类内实现--直接在类内声明友元即可\n",
|
||
"\n",
|
||
"② 全员函数类外实现--需要提前让编译器知道全局函数的存在\n",
|
||
"\n",
|
||
"③ 建议全局函数做类内实现,用法简单,而且编译器可以直接识别。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//通过全局函数 打印Person信息\n",
|
||
"\n",
|
||
"//提前声明,提前让编译器知道Person模板类存在\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person;\n",
|
||
"\n",
|
||
"//全局函数 类外实现\n",
|
||
"//让编译器知道Person类存在后,还需要提前让编译器知道printPerson2全局函数存在\n",
|
||
"template<class T1, class T2>\n",
|
||
"void printPerson2(Person<T1, T2> p) //全局函数,所以不需要加作用域\n",
|
||
"{\n",
|
||
" cout << \"类外实现--姓名:\" << p.m_Name << \" 年龄:\" << p.m_Age << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"template<class T1,class T2>\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
" //全局函数 类内实现\n",
|
||
" friend void printPerson(Person<T1, T2> p)\n",
|
||
" {\n",
|
||
" cout << \"类内实现--姓名:\" << p.m_Name << \" 年龄:\" << p.m_Age<<endl;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //全局函数 类外实现\n",
|
||
" //如果全局函数\n",
|
||
" friend void printPerson2<>(Person<T1, T2> p); //加一个空模板参数列表,表示是函数模板声明,而不是普通函数的声明 \n",
|
||
"\n",
|
||
" //只有前面让提前让编译器知道printPerson2存在,由于printPerson2里面有Person类,所以还需要提前让编译器知道Person类存在,才能申明全局函数类外实现:friend void printPerson2<>(Person<T1, T2> p);\n",
|
||
"public:\n",
|
||
" Person(T1 name, T2 age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
"private:\n",
|
||
" T1 m_Name;\n",
|
||
" T2 m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//1、全局函数在类内实现\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" Person<string, int>p(\"Tom\", 20);\n",
|
||
" printPerson(p);\n",
|
||
"}\n",
|
||
"\n",
|
||
"//2、全局函数在类外实现\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" Person<string, int>p(\"Jerry\", 20);\n",
|
||
" printPerson2(p);\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果:\n",
|
||
"- 类内实现--姓名:Tom 年龄:20 \n",
|
||
"- 类外实现--姓名:Jerry 年龄:20 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 3.9 类模板案例"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.9.1 案例描述"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"案例描述:实现一个通用的数组类,要求如下: \n",
|
||
"1. 可以对内置数据类型以及自定义数据类型的数据进行存储。\n",
|
||
"2. 将数组中的数据存储到堆区。\n",
|
||
"3. 构造函数中可以传入数组的容量。\n",
|
||
"4. 提供对应的拷贝构造函数以及operator=防止浅拷贝问题。\n",
|
||
"5. 提供尾插法和尾删法对数组中的数据进行增加和删除。\n",
|
||
"6. 可以通过下标的方式访问数组中的元素。\n",
|
||
"7. 可以获取数组中当前元素个数和数组的容量。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3.9.2 案例代码"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"//自己的通用的数组类\n",
|
||
"#pragma once\n",
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"template<class T>\n",
|
||
"class MyArray\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" //有参构造 参数为容量\n",
|
||
" MyArray(int capacity)\n",
|
||
" {\n",
|
||
" //cout << \"MyArray有参构造调用\" << endl;\n",
|
||
" this->m_Capacity = capacity;\n",
|
||
" this->m_Size = 0;\n",
|
||
" this->pAddress = new T[this->m_Capacity]; //T[this->m_Capacity]表示类型为T的数组 \n",
|
||
" }\n",
|
||
"\n",
|
||
" //拷贝构造\n",
|
||
" MyArray(const MyArray& arr)\n",
|
||
" {\n",
|
||
" //cout << \"MyArray拷贝构造调用\" << endl;\n",
|
||
" this->m_Capacity = arr.m_Capacity;\n",
|
||
" this->m_Size = arr.m_Size;\n",
|
||
" //this->pAddress = arr.pAddress; //浅拷贝会导致堆区数据重复释放\n",
|
||
"\n",
|
||
" //深拷贝\n",
|
||
" this->pAddress = new T[arr.m_Capacity];\n",
|
||
"\n",
|
||
" //将arr中的数据都拷贝过来\n",
|
||
" for (int i = 0; i < this->m_Size; i++)\n",
|
||
" {\n",
|
||
" this->pAddress[i] = arr.pAddress[i];\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
" //operator= 防止浅拷贝问题\n",
|
||
" MyArray& operator = (const MyArray& arr)\n",
|
||
" {\n",
|
||
" //cout << \"MyArray 的 operator调用\" << endl;\n",
|
||
" //先判断原来堆区是否有数据,如果有先释放\n",
|
||
" if (this->pAddress != NULL)\n",
|
||
" {\n",
|
||
" delete[] this->pAddress;\n",
|
||
" this->pAddress = NULL;\n",
|
||
" this->m_Capacity = 0;\n",
|
||
" this->m_Size = 0;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //深拷贝\n",
|
||
" this->m_Capacity = arr.m_Capacity;\n",
|
||
" this->m_Size = arr.m_Size;\n",
|
||
" this->pAddress = new T[arr.m_Capacity];\n",
|
||
" for (int i = 0; i < this->m_Size; i++)\n",
|
||
" {\n",
|
||
" this->pAddress[i] = arr.pAddress[i];\n",
|
||
" }\n",
|
||
" return *this;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //尾插法\n",
|
||
" void Push_Back(const T& val)\n",
|
||
" {\n",
|
||
" //判断容量是否等于大小\n",
|
||
" if (this->m_Capacity == this->m_Size)\n",
|
||
" {\n",
|
||
" return;\n",
|
||
" }\n",
|
||
" this->pAddress[this->m_Size] = val; //在数组末尾插入数据\n",
|
||
" this->m_Size++; //更新数组大小\n",
|
||
" }\n",
|
||
"\n",
|
||
" //尾删法\n",
|
||
" void Pop_Back()\n",
|
||
" {\n",
|
||
" //让用户访问不到最后一个元素,即为尾删,逻辑删除\n",
|
||
" if (this->m_Size == 0)\n",
|
||
" {\n",
|
||
" return;\n",
|
||
" }\n",
|
||
" this->m_Size--;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //通过下标方式访问数组中的元素\n",
|
||
" //例如,还想arr[0]作为左值存在,要返回T的引用,把数据本身作为一个返回\n",
|
||
" T& operator[](int index)\n",
|
||
" {\n",
|
||
" return this->pAddress[index];\n",
|
||
" }\n",
|
||
" \n",
|
||
" //返回数组容量\n",
|
||
" int getCapacity()\n",
|
||
" {\n",
|
||
" return this->m_Capacity;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //返回数组大小\n",
|
||
" int getSize()\n",
|
||
" {\n",
|
||
" return this->m_Size;\n",
|
||
" }\n",
|
||
"\n",
|
||
" //析构函数\n",
|
||
" ~MyArray()\n",
|
||
" {\n",
|
||
" if (this->pAddress != NULL)\n",
|
||
" {\n",
|
||
" //cout << \"MyArray析构函数调用\" << endl;\n",
|
||
" delete[] this->pAddress;\n",
|
||
" this->pAddress = NULL;\n",
|
||
" }\n",
|
||
" }\n",
|
||
"\n",
|
||
"private:\n",
|
||
" T* pAddress; //指针指向堆区开辟的真实数组\n",
|
||
" int m_Capacity; //数组容量\n",
|
||
" int m_Size; //数组大小\n",
|
||
"};\n",
|
||
"\n",
|
||
"void printIntArray(MyArray<int>& arr)\n",
|
||
"{\n",
|
||
" for (int i = 0; i < arr.getSize(); i++)\n",
|
||
" {\n",
|
||
" cout << arr[i] << endl;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" MyArray<int>arr1(5);\n",
|
||
" \n",
|
||
" for (int i = 0; i < 5; i++)\n",
|
||
" {\n",
|
||
" //利用尾插法向数组中插入数据\n",
|
||
" arr1.Push_Back(i);\n",
|
||
" }\n",
|
||
" cout << \"arr1的打印输出为:\" << endl;\n",
|
||
"\n",
|
||
" printIntArray(arr1);\n",
|
||
" \n",
|
||
" cout << \"arr1的容量为:\" << arr1.getCapacity() << endl;\n",
|
||
" cout << \"arr1的大小为:\" << arr1.getSize() << endl;\n",
|
||
"\n",
|
||
" MyArray<int>arr2(arr1);\n",
|
||
"\n",
|
||
" cout << \"arr2的打印输出为:\" << endl;\n",
|
||
" printIntArray(arr2);\n",
|
||
"\n",
|
||
" //尾删\n",
|
||
" arr2.Pop_Back();\n",
|
||
" cout << \"arr2尾删后:\" << endl;\n",
|
||
" cout << \"arr2的容量为:\" << arr2.getCapacity() << endl;\n",
|
||
" cout << \"arr2的容量为:\" << arr2.getSize() << endl;\n",
|
||
"\n",
|
||
" MyArray<int>arr3(100);\n",
|
||
" arr3 = arr1;\n",
|
||
"}\n",
|
||
"\n",
|
||
"//测试自定义数据类型\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person() {}; //默认构造空实现\n",
|
||
" Person(string name, int age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
"\n",
|
||
" string m_Name;\n",
|
||
" int m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"void printPersonArray(MyArray<Person>& arr)\n",
|
||
"{\n",
|
||
" for (int i = 0; i < arr.getSize(); i++)\n",
|
||
" {\n",
|
||
" cout << \"姓名:\" << arr[i].m_Name << \"年龄:\" << arr[i].m_Age << endl;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" MyArray<Person> arr(10);\n",
|
||
"\n",
|
||
" Person p1(\"孙悟空\", 999);\n",
|
||
" Person p2(\"韩信\", 30);\n",
|
||
" Person p3(\"妲己\", 20);\n",
|
||
" Person p4(\"赵云\", 25);\n",
|
||
" Person p5(\"安其拉\", 27);\n",
|
||
"\n",
|
||
" //将数据插入到数组中\n",
|
||
" arr.Push_Back(p1);\n",
|
||
" arr.Push_Back(p2);\n",
|
||
" arr.Push_Back(p3);\n",
|
||
" arr.Push_Back(p4);\n",
|
||
" arr.Push_Back(p5);\n",
|
||
"\n",
|
||
" //打印数组\n",
|
||
" printPersonArray(arr);\n",
|
||
"\n",
|
||
" //输出容量\n",
|
||
" cout << \"arr的容量为:\" << arr.getCapacity() << endl;\n",
|
||
"\n",
|
||
" //输出大小\n",
|
||
" cout << \"arr的大小为:\" << arr.getSize() << endl;\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main() {\n",
|
||
"\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- arr1的打印输出为: \n",
|
||
"- 0 \n",
|
||
"- 1 \n",
|
||
"- 2 \n",
|
||
"- 3 \n",
|
||
"- 4 \n",
|
||
"- arr1的容量为:5 \n",
|
||
"- arr1的大小为:5 \n",
|
||
"- arr2的打印输出为: \n",
|
||
"- 0 \n",
|
||
"- 1 \n",
|
||
"- 2 \n",
|
||
"- 3 \n",
|
||
"- 4 \n",
|
||
"- arr2尾删后: \n",
|
||
"- arr2的容量为:5 \n",
|
||
"- arr2的容量为:4 \n",
|
||
"- 姓名:孙悟空年龄:999 \n",
|
||
"- 姓名:韩信年龄:30 \n",
|
||
"- 姓名:妲己年龄:20 \n",
|
||
"- 姓名:赵云年龄:25 \n",
|
||
"- 姓名:安其拉年龄:27 \n",
|
||
"- arr的容量为:10 \n",
|
||
"- arr的大小为:5 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 4. 模板局限性"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 4.1 模板局限性简介"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"① 模板的通用性并不是万能的。\n",
|
||
"\n",
|
||
"② 利用具体化的模板,可以解决自定义类型的通用化。\n",
|
||
"\n",
|
||
"③ 学习模板并不是为了写模板,而是在STL中能够运用系统提供的模板。"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 4.2 局限性一"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"//下面代码提供赋值操作,如果传入的a和b是一个数组,就无法实现了\n",
|
||
"//数组无法给另一个数组直接赋值\n",
|
||
"\n",
|
||
"template<class T>\n",
|
||
"void myPrint(T a, T b)\n",
|
||
"{\n",
|
||
" a = b;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 4.3 局限性二"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"//在下面代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行。\n",
|
||
"\n",
|
||
"template<class T>\n",
|
||
"void myPrint(T a, T b)\n",
|
||
"{\n",
|
||
" if (a > b) { ... };\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## 4.4 模板具体实现"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#include <iostream>\n",
|
||
"using namespace std;\n",
|
||
"#include<string>\n",
|
||
"\n",
|
||
"//模板局限性\n",
|
||
"//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现\n",
|
||
"\n",
|
||
"class Person\n",
|
||
"{\n",
|
||
"public:\n",
|
||
" Person(string name, int age)\n",
|
||
" {\n",
|
||
" this->m_Name = name;\n",
|
||
" this->m_Age = age;\n",
|
||
" }\n",
|
||
" string m_Name;\n",
|
||
" int m_Age;\n",
|
||
"};\n",
|
||
"\n",
|
||
"//对比两个数据是否相等的函数\n",
|
||
"template<class T>\n",
|
||
"bool myCompare(T &a, T &b)\n",
|
||
"{\n",
|
||
" if (a == b) //(a == b)能判断整型、浮点型数据是否相等,但是没有办法判断Person类型与Person类型相等比较,但是可以通过==运算符重载,来判断Person类型的p1和Person类型的p2是否相等\n",
|
||
" {\n",
|
||
" return true;\n",
|
||
" }\n",
|
||
" else\n",
|
||
" {\n",
|
||
" return false;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"//利用具体化的Person(类)版本实现代码,具体化优先调用\n",
|
||
"template<> bool myCompare(Person & p1, Person & p2) //template<>表示这是一个模板重载的版本,Person表示这是重载的person的模板 \n",
|
||
"{\n",
|
||
" if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)\n",
|
||
" {\n",
|
||
" return true;\n",
|
||
" }·\n",
|
||
" else\n",
|
||
" {\n",
|
||
" return false;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test01()\n",
|
||
"{\n",
|
||
" int a = 10;\n",
|
||
" int b = 20;\n",
|
||
" \n",
|
||
" bool ret = myCompare(a, b);\n",
|
||
"\n",
|
||
" if (ret)\n",
|
||
" {\n",
|
||
" cout << \"a==b\" << endl;\n",
|
||
" }\n",
|
||
" else\n",
|
||
" {\n",
|
||
" cout << \"a!=b\" << endl;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"void test02()\n",
|
||
"{\n",
|
||
" Person p1(\"Tom\", 10);\n",
|
||
" Person p2(\"Tom\", 10);\n",
|
||
"\n",
|
||
" bool ret = myCompare(p1, p2);\n",
|
||
" if (ret)\n",
|
||
" {\n",
|
||
" cout << \"p1==p2\" << endl;\n",
|
||
" }\n",
|
||
" else\n",
|
||
" {\n",
|
||
" cout << \"p1!=p2\" << endl;\n",
|
||
" }\n",
|
||
"}\n",
|
||
"\n",
|
||
"int main()\n",
|
||
"{\n",
|
||
" test01();\n",
|
||
" test02();\n",
|
||
"\n",
|
||
" system(\"pause\");\n",
|
||
"\n",
|
||
" return 0;\n",
|
||
"}"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"运行结果: \n",
|
||
"- a!=b \n",
|
||
"- p1==p2 \n",
|
||
"- 请按任意键继续. . ."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3.6.3",
|
||
"language": "python",
|
||
"name": "python3.6.3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.6.3"
|
||
},
|
||
"toc": {
|
||
"base_numbering": 1,
|
||
"nav_menu": {},
|
||
"number_sections": false,
|
||
"sideBar": true,
|
||
"skip_h1_title": false,
|
||
"title_cell": "Table of Contents",
|
||
"title_sidebar": "Contents",
|
||
"toc_cell": false,
|
||
"toc_position": {
|
||
"height": "calc(100% - 180px)",
|
||
"left": "10px",
|
||
"top": "150px",
|
||
"width": "423.594px"
|
||
},
|
||
"toc_section_display": true,
|
||
"toc_window_display": true
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|