Files
张宗平 13b3ebbe14 课程代码仓库初始化:Part1 (144) + Part3 (29) 全量生成与验证
把川大 wiki「02.Qt方向」课程代码整理为 CMake 管理的可编译运行项目。

Part1 C/C++ 强化 (p01/, 144 目标, host gcc/g++ 构建, 全绿):
- 修复全部编译失败:补 <cstring>/<fstream>/<iomanip>/<vector> 等缺失头
  (common_fix + infer_stl_includes 自动检测注入)、修正 pause() 壳注入
  (改检测已转换后的 pause 调用)、namespace 提升出函数体、const 成员函数
  正确性、dedupe 不再破坏函数重载集、K&R 隐式 int / 动态异常规范等
  C++17 移除特性的可编译等价改写。
- 目录采用深缩写 p01/ch04/s03/ (原 part1_cpp/ch04_class_object/03_ctor_dtor)。

Part3 Qt 桌面 (p03/, 29 目标, 隔离 Qt 5.14.2 构建, 全绿):
- gen_part3.py: Qt 外壳模板 (main+QApplication+show, QTimer 自动退出便于
  offscreen 验证)、AUTOMOC + .moc include、rewrite_* 处理散文混入/重载/
  资源依赖、生成占位 png/gif + .qrc + rundata 样例数据。
- 修正 QLable 笔误、全角分号、.→->、Windows 路径、QApplication 阻塞事件
  循环改为 QCoreApplication 等。

任务1 概念/版本验证:
- tools/std_probe.py: 跨 -std= 编译探针 (--pedantic-errors 让已废除特性硬失败)。
- tools/demo_versions/: K&R 隐式 int、三目左值、void* 转换、enum 赋整、
  const 经指针、动态异常规范 共 6 个跨版本演示。
- docs/VERSION_NOTES.md: 每条「原文说法→C17/C++17 是否成立→何版本成立→已验证」。

文档: 顶层 README、docs/SOURCE_PAGES.md (页面→目录映射)、
docs/ERRATA.md (Part1 修正)、docs/ERRATA_part3.md (Part3 修正)。
另修复 tools/run.sh / run_qt.sh 的 ${1:?...} 引号语法 bug。

隔离 Qt 验证: ldd 0 系统 Qt 引用; 173/173 目标全绿; p03 offscreen 运行通过。
2026-06-30 14:16:55 +08:00

1 line
20 KiB
JSON
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"id":"58954472","type":"page","status":"current","title":"05.C++模板","version":{"by":{"type":"known","username":"ethanliu","userKey":"2c90931b6cfb654f016d5c69becc0001","profilePicture":{"path":"/images/icons/profilepics/default.svg","width":48,"height":48,"isDefault":true},"displayName":"刘浩","_links":{"self":"https://wiki.suncaper.net/rest/api/user?key=2c90931b6cfb654f016d5c69becc0001"},"_expandable":{"status":""}},"when":"2022-07-09T01:51:24.000Z","message":"","number":1,"minorEdit":false,"hidden":false,"_links":{"self":"https://wiki.suncaper.net/rest/experimental/content/58954472/version/1"},"_expandable":{"content":"/rest/api/content/58954472"}},"body":{"storage":{"value":"<ac:layout><ac:layout-section ac:type=\"two_right_sidebar\"><ac:layout-cell><h2><span>5.1 </span>模板概论</h2><p>c++提供了函数模板<span>(function template.)</span>所谓函数模板,<strong>实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。</strong>凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。</p><ul><li>c++提供两种模板机制<span>:</span><strong>函数模板</strong>和<strong>类模板</strong></li><li>类属<span> - </span>类型参数化,又称参数模板</li></ul><p><strong>总结:</strong></p><ul><li>模板把函数或类要处理的数据类型参数化,表现为参数的多态性,成为类属。</li><li>模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。</li></ul><h2><span>5.2 </span>函数模板</h2><p>5.2.1 什么是函数模板?</p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"b29ed2e8-d205-4409-bba4-3e596b20464b\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//交换int数据\nvoid SwapInt(int& a,int& b){\n\tint temp = a;\n\ta = b;\n\tb = temp;\n}\n\n//交换char数据\nvoid SwapChar(char& a,char& b){\n\tchar temp = a;\n\ta = b;\n\tb = temp;\n}\n//问题:如果我要交换double类型数据,那么还需要些一个double类型数据交换的函数\n//繁琐,写的函数越多,当交换逻辑发生变化的时候,所有的函数都需要修改,无形当中增加了代码的维护难度\n\n//如果能把类型作为参数传递进来就好了,传递int就是Int类型交换,传递char就是char类型交换\n//我们有一种技术,可以实现类型的参数化---函数模板\n\n\n//class 和 typename都是一样的,用哪个都可以\ntemplate<class T>\nvoid MySwap(T& a,T& b){\n\tT temp = a;\n\ta = b;\n\tb = temp;\n}\n\nvoid test01(){\n\t\n\tint a = 10;\n\tint b = 20;\n\tcout << \"a:\" << a << \" b:\" << b << endl;\n\t//1. 这里有个需要注意点,函数模板可以自动推导参数的类型\n\tMySwap(a,b);\n\tcout << \"a:\" << a << \" b:\" << b << endl;\n\n\tchar c1 = 'a';\n\tchar c2 = 'b';\n\tcout << \"c1:\" << c1 << \" c2:\" << c2 << endl;\n\t//2. 函数模板可以自动类型推导,那么也可以显式指定类型\n\tMySwap<char>(c1, c2);\n\tcout << \"c1:\" << c1 << \" c2:\" << c2 << endl;\n}]]></ac:plain-text-body></ac:structured-macro><p>5.2.2 课堂练习</p><table><colgroup><col /></colgroup><tbody><tr><td><p><strong>使用函数模板实现对</strong><strong>char</strong><strong>和<span>int</span>类型数组进行排序?</strong></p></td></tr></tbody></table><h2><span>5.3 </span>函数模板和普通函数区别</h2><ul><li>函数模板不允许自动类型转化</li><li>普通函数能够自动进行类型转化</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"30721a88-0a46-4e7c-a7c0-e05be4cb6e96\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//函数模板\ntemplate<class T>\nT MyPlus(T a, T b){\n\tT ret = a + b;\n\treturn ret;\n}\n\n//普通函数\nint MyPlus(int a,char b){\n\tint ret = a + b;\n\treturn ret;\n}\n\nvoid test02(){\n\n\tint a = 10;\n\tchar b = 'a';\n\n\t//调用函数模板,严格匹配类型\n\tMyPlus(a, a);\n\tMyPlus(b, b);\n\t//调用普通函数\n\tMyPlus(a, b);\n\t//调用普通函数 普通函数可以隐式类型转换\n\tMyPlus(b, a);\n\n\t//结论:\n\t//函数模板不允许自动类型转换,必须严格匹配类型\n\t//普通函数可以进行自动类型转换\n}]]></ac:plain-text-body></ac:structured-macro><h2><span>5.4 </span>函数模板和普通函数在一起调用规则</h2><ul><li>c++编译器优先考虑普通函数</li><li>可以通过空模板实参列表的语法限定编译器只能通过模板匹配</li><li>函数模板可以像普通函数那样可以被重载</li><li>如果函数模板可以产生一个更好的匹配,那么选择模板</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"f93bd0d8-fbf6-4b07-bbea-10d1ec784a58\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//函数模板\ntemplate<class T>\nT MyPlus(T a, T b){\n\tT ret = a + b;\n\treturn ret;\n}\n\n//普通函数\nint MyPlus(int a, int b){\n\tint ret = a + b;\n\treturn ret;\n}\n\nvoid test03(){\n\tint a = 10;\n\tint b = 20;\n\tchar c = 'a';\n\tchar d = 'b';\n\t//如果函数模板和普通函数都能匹配,c++编译器优先考虑普通函数\n\tcout << MyPlus(a, b) << endl;\n\t//如果我必须要调用函数模板,那么怎么办?\n\tcout << MyPlus<>(a, b) << endl;\n\t//此时普通函数也可以匹配,因为普通函数可以自动类型转换\n\t//但是此时函数模板能够有更好的匹配\n\t//如果函数模板可以产生一个更好的匹配,那么选择模板\n\tcout << MyPlus(c,d);\n}\n\n//函数模板重载\ntemplate<class T>\nT MyPlus(T a, T b, T c){\n\tT ret = a + b + c;\n\treturn ret;\n}\n\nvoid test04(){\n\n\tint a = 10;\n\tint b = 20;\n\tint c = 30;\n\tcout << MyPlus(a, b, c) << endl;\n\t//如果函数模板和普通函数都能匹配,c++编译器优先考虑普通函数\n}]]></ac:plain-text-body></ac:structured-macro><h2><span>5.5 </span>模板机制剖析</h2><p><strong>思考<span>:</span>为什么函数模板可以和普通函数放在一起<span>?c++</span>编译器是如何实现函数模板机制的?</strong></p><h3><span>5.5.1</span>编译过程</h3><p>hello.cpp程序是高级<span>c</span>语言程序,这种程序易于被人读懂。为了在系统上运行<span>hello.c</span>程序,每一条<span>c</span>语句都必须转化为低级的机器指令。然后将这些机器指令打包成可执行目标文件格式,并以二进制形式存储于磁盘中。</p><p>预处理<span>(Pre-processing) -&gt; </span>编译<span>(Compiling) -&gt;</span>汇编<span>(Assembling) -&gt; </span>链接<span>(Linking)</span></p><h3><span>5.5.2 </span>模板实现机制</h3><p><strong>函数模板机制结论:</strong></p><ul><li><strong>编译器并不是把函数模板处理成能够处理任何类型的函数</strong></li><li><strong>函数模板通过具体类型产生不同的函数</strong></li><li><strong>编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。</strong></li></ul><h2><span>5.6</span>模板的局限性</h2><p><strong>假设有如下模板函数:</strong></p><p><strong>       template&lt;class T&gt;</strong></p><p><strong>       void f(T a, T b)</strong></p><p><strong>       { … }</strong></p><p><strong>如果代码实现时定义了赋值操作<span> a = b</span>,但是<span>T</span>为数组,这种假设就不成立了</strong></p><p><strong>同样,如果里面的语句为判断语句<span> if(a&gt;b),</span>但<span>T</span>如果是结构体,该假设也不成立,另外如果是传入的数组,数组名为地址,因此它比较的是地址,而这也不是我们所希望的操作。</strong></p><p><strong>       总之,编写的模板函数很可能无法处理某些类型,另一方面,有时候通用化是有意义的,但<span>C++</span>语法不允许这样做。为了解决这种问题,可以提供模板的重载,为这些特定的类型提供具体化的模板。</strong></p><p><br /></p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"daed97d5-397e-4996-a961-d1e222c265fa\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Person\n{\npublic:\n\tPerson(string name, int age)\n\t{\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\n\tstring mName;\n\tint mAge;\n};\n\n//普通交换函数\ntemplate <class T>\nvoid mySwap(T &a,T &b)\n{\n\tT temp = a;\n\ta = b; \n\tb = temp;\n}\n//第三代具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型\n//具体化优先于常规模板\ntemplate<>void mySwap<Person>(Person &p1, Person &p2)\n{\n\tstring nameTemp;\n\tint ageTemp;\n\n\tnameTemp = p1.mName;\n\tp1.mName = p2.mName;\n\tp2.mName = nameTemp;\n\n\tageTemp = p1.mAge;\n\tp1.mAge = p2.mAge;\n\tp2.mAge = ageTemp;\n\n}\n\nvoid test()\n{\n\tPerson P1(\"Tom\", 10);\n\tPerson P2(\"Jerry\", 20);\n\n\tcout << \"P1 Name = \" << P1.mName << \" P1 Age = \" << P1.mAge << endl;\n\tcout << \"P2 Name = \" << P2.mName << \" P2 Age = \" << P2.mAge << endl;\n\tmySwap(P1, P2);\n\tcout << \"P1 Name = \" << P1.mName << \" P1 Age = \" << P1.mAge << endl;\n\tcout << \"P2 Name = \" << P2.mName << \" P2 Age = \" << P2.mAge << endl;\n}\n\n]]></ac:plain-text-body></ac:structured-macro><p><br /></p><h2><span>5.7 </span>类模板</h2><h3><span>5.7.1 </span>类模板基本概念</h3><p>类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。</p><ul><li>类模板用于实现类所需数据的类型参数化</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"973a517e-5c9b-4f70-a623-64e82be1ec91\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[template<class NameType, class AgeType>\nclass Person\n{\npublic:\n\tPerson(NameType name, AgeType age)\n\t{\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\n\tvoid showPerson()\n\t{\n\t\tcout << \"name: \" << this->mName << \" age: \" << this->mAge << endl;\n\t}\npublic:\n\tNameType mName;\n\tAgeType mAge;\n};\n\nvoid test01()\n{\n\t//Person P1(\"德玛西亚\",18); // 类模板不能进行类型自动推导 \n\tPerson<string, int>P1(\"德玛西亚\", 18);\n\tP1.showPerson();\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>5.7.2 </span>类模板做函数参数</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"dee49617-93ce-4943-bcc9-e98555da31b9\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//类模板\ntemplate<class NameType, class AgeType>\nclass Person{\npublic:\n\tPerson(NameType name, AgeType age){\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\n\tvoid PrintPerson(){\n\t\tcout << \"Name:\" << this->mName << \" Age:\" << this->mAge << endl;\n\t}\npublic:\n\tNameType mName;\n\tAgeType mAge;\n};\n\n//类模板做函数参数\nvoid DoBussiness(Person<string,int>& p){\n\tp.mAge += 20;\n\tp.mName += \"_vip\";\n\tp.PrintPerson();\n}\n\nint main(){\n\n\tPerson<string, int> p(\"John\", 30);\n\tDoBussiness(p);\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>5.7.3 </span>类模板派生普通类</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"cddc0b6d-bd86-4b13-8736-b71a2a4dea59\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//类模板\ntemplate<class T>\nclass MyClass{\npublic:\n\tMyClass(T property){\n\t\tthis->mProperty = property;\n\t}\npublic:\n\tT mProperty;\n};\n\n//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的\n//这样c++编译器才能知道给子类分配多少内存\n\n//普通派生类\nclass SubClass : public MyClass<int>{\npublic:\n\tSubClass(int b) : MyClass<int>(20){\n\t\tthis->mB = b;\n\t}\npublic:\n\tint mB;\n};]]></ac:plain-text-body></ac:structured-macro><h3><span>5.7.4 </span>类模板派生类模板</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"388a2946-e912-4c78-a255-92bfa657c0d2\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//父类类模板\ntemplate<class T>\nclass Base\n{\n\tT m;\n};\ntemplate<class T >\nclass Child2 : public Base<double> //继承类模板的时候,必须要确定基类的大小\n{\npublic:\n\tT mParam;\n};\n\nvoid test02()\n{\n\tChild2<int> d2;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>5.7.5 </span>类模板类内实现</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"160621e1-7831-4bab-9d2c-a73ad8b2f1cd\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[template<class NameType, class AgeType>\nclass Person\n{\npublic:\n\tPerson(NameType name, AgeType age)\n\t{\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\n\tvoid showPerson()\n\t{\n\t\tcout << \"name: \" << this->mName << \" age: \" << this->mAge << endl;\n\t}\npublic:\n\tNameType mName;\n\tAgeType mAge;\n};\n\nvoid test01()\n{\n\t//Person P1(\"德玛西亚\",18); // 类模板不能进行类型自动推导 \n\tPerson<string, int>P1(\"德玛西亚\", 18);\n\tP1.showPerson();\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>5.7.6 </span>类模板类外实现</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"246496ff-3ca0-4180-a3f8-9d3f6d19b73e\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[#define _CRT_SECURE_NO_WARNINGS\n#include<iostream>\n#include<string>\nusing namespace std;\n\ntemplate<class T1, class T2>\nclass Person{\npublic:\n\tPerson(T1 name, T2 age);\n\tvoid showPerson();\n\npublic:\n\tT1 mName;\n\tT2 mAge;\n};\n\n\n//类外实现\ntemplate<class T1, class T2>\nPerson<T1, T2>::Person(T1 name, T2 age){\n\tthis->mName = name;\n\tthis->mAge = age;\n}\n\n\ntemplate<class T1, class T2>\nvoid Person<T1, T2>::showPerson(){\n\tcout << \"Name:\" << this->mName << \" Age:\" << this->mAge << endl;\n}\n\nvoid test()\n{\n\tPerson<string, int> p(\"Obama\", 20);\n\tp.showPerson();\n}\n\nint main(){\n\n\ttest();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3>5.7.7    模板类碰到友元函数</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"10b7ef90-43f7-4c5f-820d-d379c524fd06\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[#define _CRT_SECURE_NO_WARNINGS\n#include<iostream>\nusing namespace std;\n#include <string>\n\ntemplate<class T1, class T2> class Person;\n//告诉编译器这个函数模板是存在\ntemplate<class T1, class T2> void PrintPerson2(Person<T1, T2>& p);\n\n//友元函数在类内实现\ntemplate<class T1, class T2>\nclass Person{\n\t//1. 友元函数在类内实现\n\tfriend void PrintPerson(Person<T1, T2>& p){\n\t\tcout << \"Name:\" << p.mName << \" Age:\" << p.mAge << endl;\n\t}\n\n\t//2.友元函数类外实现\n\t//告诉编译器这个函数模板是存在\n\tfriend void PrintPerson2<>(Person<T1, T2>& p);\n\n\t//3. 类模板碰到友元函数模板\n\ttemplate<class U1, class U2>\n\tfriend void PrintPerson(Person<U1, U2>& p);\n\npublic:\n\tPerson(T1 name, T2 age){\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\n\tvoid showPerson(){\n\t\tcout << \"Name:\" << this->mName << \" Age:\" << this->mAge << endl;\n\t}\nprivate:\n\tT1 mName;\n\tT2 mAge;\n};\n\nvoid test01()\n{\n\tPerson <string, int>p(\"Jerry\", 20);\n\tPrintPerson(p);\n}\n\n\n// 类模板碰到友元函数\n//友元函数类外实现 加上<>空参数列表,告诉编译去匹配函数模板\ntemplate<class T1 , class T2>\nvoid PrintPerson2(Person<T1, T2>& p)\n{\n\tcout << \"Name2:\" << p.mName << \" Age2:\" << p.mAge << endl;\n}\n\nvoid test02()\n{\n\tPerson <string, int>p(\"Jerry\", 20);\n\tPrintPerson2(p); //不写可以编译通过,写了之后,会找PrintPerson2的普通函数调用,因为写了普通函数PrintPerson2的声明\t\n}\n\nint main(){\n\n\t//test01();\n\ttest02();\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h2>5.8         类模板的应用</h2><p>设计一个数组模板类<span>(MyArray),</span>完成对不同类型元素的管理</p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"3704f744-e554-4557-bb70-ed76e05c5b9e\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[#pragma once\ntemplate<class T>\nclass MyArray\n{\npublic:\n\texplicit MyArray(int capacity)\n\t{\n\t\tthis->m_Capacity = capacity;\n\t\tthis->m_Size = 0;\n\t\t// 如果T是对象,那么这个对象必须提供默认的构造函数\n\t\tpAddress = new T[this->m_Capacity];\n\t}\n\n\t//拷贝构造\n\tMyArray(const MyArray & arr)\n\t{\n\t\tthis->m_Capacity = arr.m_Capacity;\n\t\tthis->m_Size = arr.m_Size;\n\t\tthis->pAddress = new T[this->m_Capacity];\n\t\tfor (int i = 0; i < this->m_Size;i++)\n\t\t{\n\t\t\tthis->pAddress[i] = arr.pAddress[i];\n\t\t}\n\t}\n\n\t//重载[] 操作符 arr[0]\n\tT& operator [](int index)\n\t{\n\t\treturn this->pAddress[index]; \n\t}\n\t//尾插法\n\tvoid Push_back(const T & val)\n\t{\n\t\tif (this->m_Capacity == this->m_Size)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tthis->pAddress[this->m_Size] = val;\n\t\tthis->m_Size++;\n\t}\n\tvoid Pop_back()\n\t{\n\t\tif (this->m_Size == 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tthis->m_Size--;\n\t}\n\tint\tgetSize()\n\t{\n\t\treturn this->m_Size;\n\t}\n\t//析构\n\t~MyArray()\n\t{\n\t\tif (this->pAddress != NULL)\n\t\t{\n\t\t\tdelete[] this->pAddress;\n\t\t\tthis->pAddress = NULL;\n\t\t\tthis->m_Capacity = 0; \n\t\t\tthis->m_Size = 0;\n\t\t}\n\t}\n\nprivate:\n\tT * pAddress; //指向一个堆空间,这个空间存储真正的数据\n\tint m_Capacity; //容量\n\tint m_Size; // 大小\n};\n\n测试代码:\n\n\nclass Person{\npublic:\n\tPerson(){}\n\tPerson(string name, int age){\n\t\tthis->mName = name;\n\t\tthis->mAge = age;\n\t}\npublic:\n\tstring mName;\n\tint mAge;\n};\n\n\nvoid PrintMyArrayInt(MyArray<int>& arr){\n\tfor (int i = 0; i < arr.getSize(); i++){\n\t\tcout << arr[i] << \" \";\n\t}\n\tcout << endl;\n}\n\nvoid PrintMyPerson(MyArray<Person>& personArr)\n{\n\tfor (int i = 0; i < personArr.getSize(); i++){\n\t\tcout << \"姓名:\" << personArr[i].mName << \" 年龄: \" << personArr[i].mAge << endl;\n\t}\n\t\n}\n\t\n\tMyArray<int> myArrayInt(10);\n\tfor (int i = 0; i < 9; i++)\n\t{\n\t\tmyArrayInt.Push_back(i);\n\t}\n\tmyArrayInt.Push_back(100);\n\tPrintMyArrayInt(myArrayInt);\n\nMyArray<Person> myArrayPerson(10);\n\tPerson p1(\"德玛西亚\", 30);\n\tPerson p2(\"提莫\", 20);\n\tPerson p3(\"孙悟空\",18);\n\tPerson p4(\"赵信\", 15);\n\tPerson p5(\"赵云\", 24);\n\tmyArrayPerson.Push_back(p1);\n\tmyArrayPerson.Push_back(p2);\n\tmyArrayPerson.Push_back(p3);\n\tmyArrayPerson.Push_back(p4);\n\tmyArrayPerson.Push_back(p5);]]></ac:plain-text-body></ac:structured-macro><p><br /></p><p><br /></p></ac:layout-cell><ac:layout-cell><p><br /></p></ac:layout-cell></ac:layout-section></ac:layout>","representation":"storage","_expandable":{"content":"/rest/api/content/58954472"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954472","edit":"/pages/resumedraft.action?draftId=58954472","tinyui":"/x/6JKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954472"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954472/child","restrictions":"/rest/api/content/58954472/restriction/byOperation","history":"/rest/api/content/58954472/history","ancestors":"","descendants":"/rest/api/content/58954472/descendant","space":"/rest/api/space/2CT"}}