Files
scuc-qt-course/tools/wiki_data/bodies/58954456.json
T
张宗平 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
10 KiB
JSON
Raw 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.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"id":"58954456","type":"page","status":"current","title":"04.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/58954456/version/1"},"_expandable":{"content":"/rest/api/content/58954456"}},"body":{"storage":{"value":"<ac:layout><ac:layout-section ac:type=\"two_right_sidebar\"><ac:layout-cell><h2><span>4.4 C++</span>面向对象模型初探</h2><h3><span>4.4.1 </span>成员变量和函数的存储</h3><p>在<span>c</span>语言中,“分开来声明的,也就是说,语言本身并没有支持“数据”和“函数”之间的关联性我们把这种程序方法称为“程序性的”,由一组“分布在各个以功能为导航的函数中”的算法驱动,它们处理的是共同的外部数据。</p><p><span> </span></p><p>c++实现了“封装”,那么数据<span>(</span>成员属性<span>)</span>和操作<span>(</span>成员函数<span>)</span>是什么样的呢?</p><p>“数据”和“处理数据的操作<span>(</span>函数<span>)</span>”是分开存储的。</p><ul><li>c++中的<strong>非静态数据成员</strong>直接内含在类对象中,就像<span>c struct</span>一样。</li><li>成员函数<span>(member function)</span>虽然内含在<span>class</span>声明之内,却不出现在对象中。</li><li>每一个非内联成员函数<span>(non-inline member function)</span>只会诞生一份函数实例<span>.</span></li></ul><p><br /></p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"78bef3f0-a75f-4cc8-9b5e-9cf5db57006a\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class MyClass01{\npublic:\n\tint mA;\n};\n\nclass MyClass02{\npublic:\n\tint mA;\n\tstatic int sB;\n};\n\nclass MyClass03{\npublic:\n\tvoid printMyClass(){\n\t\tcout << \"hello world!\" << endl;\n\t}\npublic:\n\tint mA;\n\tstatic int sB;\n};\n\nclass MyClass04{\npublic:\n\tvoid printMyClass(){\n\t\tcout << \"hello world!\" << endl;\n\t}\n\tstatic void ShowMyClass(){\n\t\tcout << \"hello world\" << endl;\n\t}\npublic:\n\tint mA;\n\tstatic int sB;\n};\n\nint main(){\n\n\tMyClass01 mclass01;\n\tMyClass02 mclass02;\n\tMyClass03 mclass03;\n\tMyClass04 mclass04;\n\n\tcout << \"MyClass01:\" << sizeof(mclass01) << endl; //4\n\t//静态数据成员并不保存在类对象中\n\tcout << \"MyClass02:\" << sizeof(mclass02) << endl; //4\n\t//非静态成员函数不保存在类对象中\n\tcout << \"MyClass03:\" << sizeof(mclass03) << endl; //4\n\t//静态成员函数也不保存在类对象中\n\tcout << \"MyClass04:\" << sizeof(mclass04) << endl; //4\n\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>4.4.2 this</span>指针</h3><h4><span>4.4.2.1 this</span>指针工作原理</h4><p>通过上例我们知道,<span>c++</span>的数据和操作也是分开存储,并且每一个非内联成员函数<span>(non-inline member function)</span>只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码</p><p>那么问题是:这一块代码是如何区分那个对象调用自己的呢?</p><p>c++通过提供特殊的对象指针,<span>this</span>指针,解决上述问题。<span>this</span>指针指向被调用的成员函数所属的对象。</p><p> <span>      c++</span>规定,<span>this</span>指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针<span>this</span>,用以保存这个对象的地址,也就是说虽然我们没有写上<span>this</span>指针,编译器在编译的时候也是会加上的。因此<span>this</span>也称为“指向本对象的指针”,<span>this</span>指针并不是对象的一部分,不会影响<span>sizeof(</span>对象<span>)</span>的结果。</p><p>   <span>this</span>指针是<span>C++</span>实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写<span>this</span>,而是让系统进行默认设置。</p><p><strong>this指针永远指向当前对象</strong>。</p><p>成员函数通过<span>this</span>指针即可知道操作的是那个对象的数据。This指针是一种隐含指针,它隐含于每个类的非静态成员函数中。<span>This</span>指针无需定义,直接使用即可。</p><table><colgroup><col /></colgroup><tbody><tr><td><p>注意:静态成员函数内部没有<span>this</span>指针,静态成员函数不能操作非静态成员变量。</p></td></tr></tbody></table><h4><span>4.4.2.2 this</span>指针的使用</h4><ul><li>当形参和成员变量同名时,可用<span>this</span>指针来区分</li><li>在类的非静态成员函数中返回对象本身,可使用<span>return *this.</span></li></ul><p><br /></p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"a92483f9-9a9b-4828-bda3-e6101d3448ce\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Person{\npublic:\n\t//1. 当形参名和成员变量名一样时,this指针可用来区分\n\tPerson(string name,int age){\n\t\t//name = name;\n\t\t//age = age; //输出错误\n\t\tthis->name = name;\n\t\tthis->age = age;\n\t}\n\t//2. 返回对象本身的引用\n\t//重载赋值操作符\n\t//其实也是两个参数,其中隐藏了一个this指针\n\tPerson PersonPlusPerson(Person& person){\n\t\tstring newname = this->name + person.name;\n\t\tint newage = this->age + person.age;\n\t\tPerson newperson(newname, newage);\n\t\treturn newperson;\n\t}\n\tvoid ShowPerson(){\n\t\tcout << \"Name:\" << name << \" Age:\" << age << endl;\n\t}\npublic:\n\tstring name;\n\tint age;\n};\n\n//3. 成员函数和全局函数(Perosn对象相加)\nPerson PersonPlusPerson(Person& p1,Person& p2){\n\tstring newname = p1.name + p2.name;\n\tint newage = p1.age + p2.age;\n\tPerson newperson(newname,newage);\n\treturn newperson;\n}\n\nint main(){\n\n\tPerson person(\"John\",100);\n\tperson.ShowPerson();\n\n\tcout << \"---------\" << endl;\n\tPerson person1(\"John\",20);\n\tPerson person2(\"001\", 10);\n\t//1.全局函数实现两个对象相加\n\tPerson person3 = PersonPlusPerson(person1, person2);\n\tperson1.ShowPerson();\n\tperson2.ShowPerson();\n\tperson3.ShowPerson();\n\t//2. 成员函数实现两个对象相加\n\tPerson person4 = person1.PersonPlusPerson(person2);\n\tperson4.ShowPerson();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h4><span>4.4.2.3 const</span>修饰成员函数</h4><ul><li>用<span>const</span>修饰的成员函数时,const修饰<span>this</span>指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量</li><li>当成员变量类型符前用<span>mutable</span><span>修饰时例外。</span></li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"12aee074-d30f-4c5b-87b8-d4ba3434c335\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//const修饰成员函数\nclass Person{\npublic:\n\tPerson(){\n\t\tthis->mAge = 0;\n\t\tthis->mID = 0;\n\t}\n\t//在函数括号后面加上const,修饰成员变量不可修改,除了mutable变量\n\tvoid sonmeOperate() const{\n\t\t//this->mAge = 200; //mAge不可修改\n\t\tthis->mID = 10;\n\t}\n\tvoid ShowPerson(){\n\t\tcout << \"ID:\" << mID << \" mAge:\" << mAge << endl;\n\t}\nprivate:\n\tint mAge;\n\tmutable int mID;\n};\n\nint main(){\n\n\tPerson person;\n\tperson.sonmeOperate();\n\tperson.ShowPerson();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h4><span>4.4.2.4 const</span>修饰对象<span>(</span>常对象<span>)</span></h4><ul><li>常对象只能调用<span>const</span>的成员函数</li><li>常对象可访问<span> const </span>或非<span> const </span>数据成员,不能修改,除非成员用<span>mutable</span>修饰</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"48a15323-9302-4b63-8e3f-3c3beaa1a140\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Person{\npublic:\n\tPerson(){\n\t\tthis->mAge = 0;\n\t\tthis->mID = 0;\n\t}\n\tvoid ChangePerson() const{\n\t\tmAge = 100;\n\t\tmID = 100;\n\t}\n\tvoid ShowPerson(){\n this->mAge = 1000;\n\t\tcout << \"ID:\" << this->mID << \" Age:\" << this->mAge << endl;\n\t}\n\npublic:\n\tint mAge;\n\tmutable int mID;\n};\n\nvoid test(){\t\n\tconst Person person;\n\t//1. 可访问数据成员\n\tcout << \"Age:\" << person.mAge << endl;\n\t//person.mAge = 300; //不可修改\n\tperson.mID = 1001; //但是可以修改mutable修饰的成员变量\n\t//2. 只能访问const修饰的函数\n\t//person.ShowPerson();\n\tperson.ChangePerson();\n}]]></ac:plain-text-body></ac:structured-macro></ac:layout-cell><ac:layout-cell><p><br /></p></ac:layout-cell></ac:layout-section></ac:layout>","representation":"storage","_expandable":{"content":"/rest/api/content/58954456"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954456","edit":"/pages/resumedraft.action?draftId=58954456","tinyui":"/x/2JKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954456"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954456/child","restrictions":"/rest/api/content/58954456/restriction/byOperation","history":"/rest/api/content/58954456/history","ancestors":"","descendants":"/rest/api/content/58954456/descendant","space":"/rest/api/space/2CT"}}