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
8.4 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":"58954473","type":"page","status":"current","title":"06.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/58954473/version/1"},"_expandable":{"content":"/rest/api/content/58954473"}},"body":{"storage":{"value":"<ac:layout><ac:layout-section ac:type=\"two_right_sidebar\"><ac:layout-cell><p>类型转换<span>(cast)</span>是将一种数据类型转换成另一种数据类型。例如,如果将一个整型值赋给一个浮点类型的变量,编译器会暗地里将其转换成浮点类型。</p><p>转换是非常有用的,但是它也会带来一些问题,比如在转换指针时,我们很可能将其转换成一个比它更大的类型,但这可能会破坏其他的数据。</p><p>应该小心类型转换,因为转换也就相当于对编译器说:忘记类型检查,把它看做其他的类型。</p><p>一般情况下,尽量少的去使用类型转换,除非用来解决非常特殊的问题。</p><p><span> </span></p><table><tbody><tr><td><p>    无论什么原因,任何一个程序如果使用很多类型转换都值得怀疑<span>.</span></p></td></tr></tbody></table><p><span> </span></p><p>标准<span>c++</span>提供了一个显示的转换的语法,来替代旧的<span>C</span>风格的类型转换。</p><p>使用<span>C</span>风格的强制转换可以把想要的任何东西转换成我们需要的类型。那为什么还需要一个新的<span>C++</span>类型的强制转换呢?</p><p>新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。<span>C++</span>风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。</p><p><span> </span></p><h2><span>6.1 </span>静态转换<span>(static_cast)</span></h2><ul><li>用于<span><a href=\"http://baike.baidu.com/view/2405425.htm\">类层次结构</a></span>中基类(父类)和<span><a href=\"http://baike.baidu.com/view/535532.htm\">派生类</a></span>(子类)之间指针或引用的转换。</li><li>进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;</li><li>进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。</li><li>用于基本数据类型之间的转换,如把<span>int</span>转换成<span>char</span>,把<span>char</span>转换成<span>int</span>。这种转换的安全性也要开发人员来保证。</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"b11d3ea1-fb26-4b3a-a201-86f8dfed7d77\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Animal{};\nclass Dog : public Animal{};\nclass Other{};\n\n//基础数据类型转换\nvoid test01(){\n\tchar a = 'a';\n\tdouble b = static_cast<double>(a);\n}\n\n//继承关系指针互相转换\nvoid test02(){\n\t//继承关系指针转换\n\tAnimal* animal01 = NULL;\n\tDog* dog01 = NULL;\n\t//子类指针转成父类指针,安全\n\tAnimal* animal02 = static_cast<Animal*>(dog01);\n\t//父类指针转成子类指针,不安全\n\tDog* dog02 = static_cast<Dog*>(animal01);\n}\n\n//继承关系引用相互转换\nvoid test03(){\n\n\tAnimal ani_ref;\n\tDog dog_ref;\n\t//继承关系指针转换\n\tAnimal& animal01 = ani_ref;\n\tDog& dog01 = dog_ref;\n\t//子类指针转成父类指针,安全\n\tAnimal& animal02 = static_cast<Animal&>(dog01);\n\t//父类指针转成子类指针,不安全\n\tDog& dog02 = static_cast<Dog&>(animal01);\n}\n\n//无继承关系指针转换\nvoid test04(){\n\t\n\tAnimal* animal01 = NULL;\n\tOther* other01 = NULL;\n\n\t//转换失败\n\t//Animal* animal02 = static_cast<Animal*>(other01);\n}]]></ac:plain-text-body></ac:structured-macro><h2><span>2.2 </span>动态转换<span>(dynamic_cast)</span></h2><ul><li>dynamic_cast主要用于类层次间的上行转换和下行转换;</li><li>在类层次间进行上行转换时,<span>dynamic_cast</span>和<span>static_cast</span>的效果是一样的;</li><li>在进行下行转换时,<span>dynamic_cast</span>具有类型检查的功能,比<span>static_cast</span>更安全;</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"f8c3c5c9-48f2-4d7a-8469-a0dfb5529ecb\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Animal {\npublic:\n\tvirtual void ShowName() = 0;\n};\nclass Dog : public Animal{\n\tvirtual void ShowName(){\n\t\tcout << \"I am a dog!\" << endl;\n\t}\n};\nclass Other {\npublic:\n\tvoid PrintSomething(){\n\t\tcout << \"我是其他类!\" << endl;\n\t}\n};\n\n//普通类型转换\nvoid test01(){\n\n\t//不支持基础数据类型\n\tint a = 10;\n\t//double a = dynamic_cast<double>(a);\n}\n\n//继承关系指针\nvoid test02(){\n\n\tAnimal* animal01 = NULL;\n\tDog* dog01 = new Dog;\n\n\t//子类指针转换成父类指针 可以\n\tAnimal* animal02 = dynamic_cast<Animal*>(dog01);\n\tanimal02->ShowName();\n\t//父类指针转换成子类指针 不可以\n\t//Dog* dog02 = dynamic_cast<Dog*>(animal01);\n}\n\n//继承关系引用\nvoid test03(){\n\n\tDog dog_ref;\n\tDog& dog01 = dog_ref;\n\n\t//子类引用转换成父类引用 可以\n\tAnimal& animal02 = dynamic_cast<Animal&>(dog01);\n\tanimal02.ShowName();\n}\n\n//无继承关系指针转换\nvoid test04(){\n\t\n\tAnimal* animal01 = NULL;\n\tOther* other = NULL;\n\n\t//不可以\n\t//Animal* animal02 = dynamic_cast<Animal*>(other);\n}]]></ac:plain-text-body></ac:structured-macro><h2><span>2.3 </span>常量转换<span>(const_cast)</span></h2><p>该运算符用来修改类型的<span>const</span>属性。。</p><ul><li>常量指针被转化成非常量指针,并且仍然指向原来的对象;</li><li>常量引用被转换成非常量引用,并且仍然指向原来的对象;</li></ul><p><span> </span></p><table><tbody><tr><td><p><strong>注意<span>:</span></strong>不能直接对非指针和非引用的变量使用<span>const_cast</span>操作符去直接移除它的<span>const.</span></p></td></tr></tbody></table><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"a726eee3-319d-4acf-9f8c-2b80be07c77a\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//常量指针转换成非常量指针\nvoid test01(){\n\t\n\tconst int* p = NULL;\n\tint* np = const_cast<int*>(p);\n\n\tint* pp = NULL;\n\tconst int* npp = const_cast<const int*>(pp);\n\n\tconst int a = 10; //不能对非指针或非引用进行转换\n\t//int b = const_cast<int>(a); }\n\n//常量引用转换成非常量引用\nvoid test02(){\n\nint num = 10;\n\tint & refNum = num;\n\n\tconst int& refNum2 = const_cast<const int&>(refNum);\n\t\n}]]></ac:plain-text-body></ac:structured-macro><h2><span>2.3 </span>重新解释转换<span>(reinterpret_cast)</span>。。。。。</h2><p>这是最不安全的一种转换机制,最有可能出问题。</p><p>主要用于将一种数据类型从一种类型转换为另一种类型。它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针<span>.</span></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/58954473"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954473","edit":"/pages/resumedraft.action?draftId=58954473","tinyui":"/x/6ZKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954473"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954473/child","restrictions":"/rest/api/content/58954473/restriction/byOperation","history":"/rest/api/content/58954473/history","ancestors":"","descendants":"/rest/api/content/58954473/descendant","space":"/rest/api/space/2CT"}}