Files
scuc-qt-course/tools/wiki_data/bodies/58954473.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
8.4 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.
{"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"}}