13b3ebbe14
把川大 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 运行通过。
1 line
21 KiB
JSON
1 line
21 KiB
JSON
{"id":"58954474","type":"page","status":"current","title":"07.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/58954474/version/1"},"_expandable":{"content":"/rest/api/content/58954474"}},"body":{"storage":{"value":"<ac:layout><ac:layout-section ac:type=\"two_right_sidebar\"><ac:layout-cell><h2><span>7.1 </span>异常基本概念</h2><p>Bjarne Stroustrup说:提供异常的基本目的就是为了处理上面的问题。基本思想是:让一个函数在发现了自己无法处理的错误时抛出(<span>throw</span>)一个异常,然后它的(直接或者间接)调用者能够处理这个问题。也就是《<span>C++ primer</span>》中说的:将问题检测和问题处理相分离。</p><p>一种思想:在所有支持异常处理的编程语言中(例如<span>java</span>),要认识到的一个思想:在异常处理过程中,由问题检测代码可以抛出一个对象给问题处理代码,通过这个对象的类型和内容,实际上完成了两个部分的通信,通信的内容是“出现了什么错误”。当然,各种语言对异常的具体实现有着或多或少的区别,但是这个通信的思想是不变的。</p><p><br /></p><table><colgroup><col /></colgroup><tbody><tr><td><p><strong>一句话:异常处理就是处理程序中的错误。所谓错误是指在程序运行的过程中发生的一些异常事件(如:除<span>0</span>溢出,数组下标越界,所要读取的文件不存在<span>,</span>空指针,内存不足等等)。</strong></p></td></tr></tbody></table><p><br /></p><p><strong>回顾一下:我们以前编写程序是如何处理异常?</strong></p><p>在<span>C</span>语言的世界中,对错误的处理总是围绕着两种方法:一是使用整型的返回值标识错误;二是使用<span>errno</span>宏(可以简单的理解为一个全局整型变量)去记录错误。当然<span>C++</span>中仍然是可以用这两种方法的。</p><p> 这两种方法最大的缺陷就是会出现不一致问题。例如有些函数返回<span>1</span>表示成功,返回<span>0</span>表示出错;而有些函数返回<span>0</span>表示成功,返回非<span>0</span>表示出错。<span> </span></p><p> 还有一个缺点就是函数的返回值只有一个,你通过函数的返回值表示错误代码,那么函数就不能返回其他的值。当然,你也可以通过指针或者<span>C++</span>的引用来返回另外的值,但是这样可能会令你的程序略微晦涩难懂。</p><p><br /></p><p><strong>c++</strong><strong>异常机制相比<span>C</span>语言异常处理的优势<span>?</span></strong></p><ul><li>函数的返回值可以忽略,但异常不可忽略。如果程序出现异常,但是没有被捕获,程序就会终止,这多少会促使程序员开发出来的程序更健壮一点。而如果使用<span>C</span>语言的<span>error</span>宏或者函数返回值,调用者都有可能忘记检查,从而没有对错误进行处理,结果造成程序莫名其面的终止或出现错误的结果。</li><li>整型返回值没有任何语义信息。而异常却包含语义信息,有时你从类名就能够体现出来。</li><li>整型返回值缺乏相关的上下文信息。异常作为一个类,可以拥有自己的成员,这些成员就可以传递足够的信息。</li><li>异常处理可以在调用跳级。这是一个代码编写时的问题:假设在有多个函数的调用栈中出现了某个错误,使用整型返回码要求你在每一级函数中都要进行处理。而使用异常处理的栈展开机制,只需要在一处进行处理就可以了,不需要每级函数都处理。</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"e84dccb7-8032-45df-b117-9bc03d12cf8e\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//如果判断返回值,那么返回值是错误码还是结果?\n//如果不判断返回值,那么b==0时候,程序结果已经不正确\n//A写的代码\nint A_MyDivide(int a,int b){\n\tif (b == 0){\n\t\treturn -1;\n\t}\n\n\treturn a / b;\n}\n\n//B写的代码\nint B_MyDivide(int a,int b){\n\n\tint ba = a + 100;\n\tint bb = b;\n\n\tint ret = A_MyDivide(ba, bb); //由于B没有处理异常,导致B结果运算错误\n\n\treturn ret;\n}\n\n//C写的代码\nint C_MyDivide(){\n\n\tint a = 10;\n\tint b = 0;\n\n\tint ret = B_MyDivide(a, b); //更严重的是,由于B没有继续抛出异常,导致C的代码没有办法捕获异常\n\tif (ret == -1){\n\t\treturn -1;\n\t}\n\telse{\n\t\treturn ret;\n\t}\n}\n\n//所以,我们希望:\n//1.异常应该捕获,如果你捕获,可以,那么异常必须继续抛给上层函数,你不处理,不代表你的上层不处理\n//2.这个例子,异常没有捕获的结果就是运行结果错的一塌糊涂,结果未知,未知的结果程序没有必要执行下去]]></ac:plain-text-body></ac:structured-macro><h2><span>7.2 </span>异常语法</h2><h3><span>7.2.1 </span>异常基本语法</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"aee5511b-fd02-4834-b8ce-1061aa69489f\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[int A_MyDivide(int a, int b){\n\tif (b == 0){\n\t\tthrow 0;\n\t}\n\n\treturn a / b;\n}\n\n//B写的代码 B写代码比较粗心,忘记处理异常\nint B_MyDivide(int a, int b){\n\n\tint ba = a;\n\tint bb = b;\n\n\tint ret = A_MyDivide(ba, bb) + 100; //由于B没有处理异常,导致B结果运算错误\n\n\treturn ret;\n}\n\n//C写的代码\nint C_MyDivide(){\n\n\tint a = 10;\n\tint b = 0;\n\n\tint ret = 0;\n\n//没有处理异常,程序直接中断执行\n#if 1 \n\tret = B_MyDivide(a, b);\n\n//处理异常\n#else \n\ttry{\n\t\tret = B_MyDivide(a, b); //更严重的是,由于B没有继续抛出异常,导致C的代码没有办法捕获异常\n\t}\n\tcatch (int e){\n\t\tcout << \"C_MyDivide Call B_MyDivide 除数为:\" << e << endl;\n\t}\n#endif\n\t\n\treturn ret;\n}\n\nint main(){\n\n\tC_MyDivide();\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><p><strong>总结<span>:</span></strong></p><ul><li>若有异常则通过<span>throw</span>操作创建一个异常对象并抛出。</li><li>将可能抛出异常的程序段放到<span>try</span>块之中。</li><li>如果在<span>try</span>段执行期间没有引起异常,那么跟在<span>try</span>后面的<span>catch</span>字句就不会执行。</li><li>catch子句会根据出现的先后顺序被检查,匹配的<span>catch</span>语句捕获并处理异常<span>(</span>或继续抛出异常<span>)</span></li><li>如果匹配的处理未找到,则运行函数<span>terminate</span>将自动被调用,其缺省功能调用<span>abort</span>终止程序。</li><li>处理不了的异常,可以在<span>catch</span>的最后一个分支,使用<span>throw</span>,向上抛。</li></ul><p><span> </span></p><p>c++异常处理使得异常的引发和异常的处理不必在一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。</p><h3><span>7.2.2 </span>异常严格类型匹配</h3><p>异常机制和函数机制互不干涉<span>,</span>但是<strong>捕捉方式是通过严格类型匹配</strong>。</p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"8b51da98-bda5-4f5e-8a17-256253ccb148\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[void TestFunction(){\n\t\n\tcout << \"开始抛出异常...\" << endl;\n\t//throw 10; //抛出int类型异常\n\t//throw 'a'; //抛出char类型异常\n\t//throw \"abcd\"; //抛出char*类型异常\n\tstring ex = \"string exception!\";\n\tthrow ex;\n\n}\n\nint main(){\n\n\ttry{\n\t\tTestFunction();\n\t}\n\tcatch (int){\n\t\tcout << \"抛出Int类型异常!\" << endl;\n\t}\n\tcatch (char){\n\t\tcout << \"抛出Char类型异常!\" << endl;\n\t}\n\tcatch (char*){\n\t\tcout << \"抛出Char*类型异常!\" << endl;\n\t}\n\tcatch (string){\n\t\tcout << \"抛出string类型异常!\" << endl;\n\t}\n\t//捕获所有异常\n\tcatch (...){\n\t\tcout << \"抛出其他类型异常!\" << endl;\n\t}\n\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>7.2.3 </span>栈解旋<span>(unwinding)</span></h3><p>异常被抛出后,从进入<span>try</span>块起,到异常被抛掷前,这期间在栈上构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反,这一过程称为栈的解旋<span>(unwinding).</span></p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"dce8d11f-a1f0-410c-a1a7-5659fcf7e134\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Person{\npublic:\n\tPerson(string name){\n\t\tmName = name;\n\t\tcout << mName << \"对象被创建!\" << endl;\n\t}\n\t~Person(){\n\t\tcout << mName << \"对象被析构!\" << endl;\n\t}\npublic:\n\tstring mName;\n};\n\nvoid TestFunction(){\n\t\n\tPerson p1(\"aaa\");\n\tPerson p2(\"bbb\");\n\tPerson p3(\"ccc\");\n\n\t//抛出异常\n\tthrow 10;\n}\n\nint main(){\n\n\ttry{\n\t\tTestFunction();\n\t}\n\tcatch (...){\n\t\tcout << \"异常被捕获!\" << endl;\n\t}\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>7.2.4 </span>异常接口声明</h3><ul><li>为了加强程序的可读性,可以在函数声明中列出可能抛出异常的所有类型,例如:<span>void func() throw(A,B,C);</span>这个函数<span>func</span>能够且只能抛出类型<span>A,B,C</span>及其子类型的异常。</li><li>如果在函数声明中没有包含异常接口声明,则此函数可以抛任何类型的异常,例如<span>:void func()</span></li><li>一个不抛任何类型异常的函数可声明为<span>:void func() throw()</span></li><li>如果一个函数抛出了它的异常接口声明所不允许抛出的异常<span>,unexcepted</span>函数会被调用,该函数默认行为调用<span>terminate</span>函数中断程序。</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"9f01aa9a-d0d0-4a52-9c5f-eee9eb99d91c\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//可抛出所有类型异常\nvoid TestFunction01(){\n\tthrow 10;\n}\n\n//只能抛出int char char*类型异常\nvoid TestFunction02() throw(int,char,char*){\n\tstring exception = \"error!\";\n\tthrow exception;\n}\n\n//不能抛出任何类型异常\nvoid TestFunction03() throw(){\n\tthrow 10;\n}\n\nint main(){\n\n\ttry{\n\t\t//TestFunction01();\n\t\t//TestFunction02();\n\t\t//TestFunction03();\n\t}\n\tcatch (...){\n\t\tcout << \"捕获异常!\" << endl;\n\t}\n\t\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><p>请分别在<span>qt vs linux</span>下做测试<span>! Qt and Linux </span>正确<span>!</span></p><h3><span>7.2.5 </span>异常变量生命周期</h3><ul><li>throw的异常是有类型的,可以是数字、字符串、类对象。</li><li>throw的异常是有类型的,<span>catch</span>需严格匹配异常类型。</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"853be07a-a0e7-4770-b950-23efe59db199\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class MyException\n{\npublic:\n\tMyException(){\n\t\tcout << \"异常变量构造\" << endl;\n\t};\n\tMyException(const MyException & e)\n\t{\n\t\tcout << \"拷贝构造\" << endl;\n\t}\n\t~MyException()\n\t{\n\t\tcout << \"异常变量析构\" << endl;\n\t}\n};\nvoid DoWork()\n{\n\tthrow new MyException(); //test1 2都用 throw MyExecption();\n}\n\nvoid test01()\n{\n\ttry\n\t{\n\t\tDoWork();\n\t}\n\tcatch (MyException e)\n\t{\n\t\tcout << \"捕获 异常\" << endl;\n\t}\n}\nvoid test02()\n{\n\ttry\n\t{\n\t\tDoWork();\n\t}\n\tcatch (MyException &e)\n\t{\n\t\tcout << \"捕获 异常\" << endl;\n\t}\n}\n\nvoid test03()\n{\n\ttry\n\t{\n\t\tDoWork();\n\t}\n\tcatch (MyException *e)\n\t{\n\t\tcout << \"捕获 异常\" << endl;\n\t\tdelete e;\n\t}\n}]]></ac:plain-text-body></ac:structured-macro><h3>7.2.6 异常的多态使用</h3><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"5e6e913c-fa9c-4c1d-aadf-612f068d7cf2\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//异常基类\nclass BaseException{\npublic:\n\tvirtual void printError(){};\n};\n\n//空指针异常\nclass NullPointerException : public BaseException{\npublic:\n\tvirtual void printError(){\n\t\tcout << \"空指针异常!\" << endl;\n\t}\n};\n//越界异常\nclass OutOfRangeException : public BaseException{\npublic:\n\tvirtual void printError(){\n\t\tcout << \"越界异常!\" << endl;\n\t}\n};\n\nvoid doWork(){\n\n\tthrow NullPointerException();\n}\n\nvoid test()\n{\n\ttry{\n\t\tdoWork();\n\t}\n\tcatch (BaseException& ex){\n\t\tex.printError();\n\t}\n}\n\n]]></ac:plain-text-body></ac:structured-macro><h2><span>7.3 C++</span>标准异常库</h2><h3><span>7.3.1 </span>标准库介绍</h3><p>标准库中也提供了很多的异常类,它们是通过类继承组织起来的。异常类继承层级结构图如下:</p><p><ac:image ac:height=\"400\"><ri:attachment ri:filename=\"image2021-5-14_14-34-14.png\" /></ac:image></p><p>每个类所在的头文件在图下方标识出来。</p><p><strong>标准异常类的成员:</strong></p><p>① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。</p><p>②<span> logic_error</span>类及其子类、<span>runtime_error</span>类及其子类,它们的构造函数是接受一个<span>string</span>类型的形式参数,用于异常信息的描述</p><p>③ 所有的异常类都有一个<span>what()</span>方法,返回<span>const char* </span>类型(<span>C</span>风格字符串)的值,描述异常信息。</p><p><br /></p><p><strong>标准异常类的具体描述:</strong></p><table><colgroup><col /><col /></colgroup><tbody><tr><td><p>异常名称</p></td><td><p>描述</p></td></tr><tr><td><p>exception</p></td><td><p>所有标准异常类的父类</p></td></tr><tr><td><p>bad_alloc</p></td><td><p>当<span>operator new and operator new[]</span>,请求分配内存失败时</p></td></tr><tr><td><p>bad_exception</p></td><td><p>这是个特殊的异常,如果函数的异常抛出列表里声明了<span>bad_exception</span>异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的<span>unexpected</span>函数中若抛出异常,不论什么类型,都会被替换为<span>bad_exception</span>类型</p></td></tr><tr><td><p>bad_typeid</p></td><td><p>使用<span>typeid</span>操作符,操作一个<span>NULL</span>指针,而该指针是带有虚函数的类,这时抛出<span>bad_typeid</span>异常</p></td></tr><tr><td><p>bad_cast</p></td><td><p>使用<span>dynamic_cast</span>转换引用失败的时候</p></td></tr><tr><td><p>ios_base::failure</p></td><td><p>io操作过程出现错误</p></td></tr><tr><td><p>logic_error</p></td><td><p>逻辑错误,可以在运行前检测的错误</p></td></tr><tr><td><p>runtime_error </p></td><td><p>运行时错误,仅在运行时才可以检测的错误</p></td></tr></tbody></table><p><strong>logic_error</strong><strong>的子类:</strong></p><table><colgroup><col /><col /></colgroup><tbody><tr><td><p>异常名称</p></td><td><p>描述</p></td></tr><tr><td><p>length_error</p></td><td><p>试图生成一个超出该类型最大长度的对象时,例如<span>vector</span>的<span>resize</span>操作</p></td></tr><tr><td><p>domain_error</p></td><td><p>参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数</p></td></tr><tr><td><p>out_of_range</p></td><td><p>超出有效范围</p><p><br /></p></td></tr><tr><td><p>invalid_argument</p></td><td><p>参数不合适。在标准库中,当利用<span>string</span>对象构造<span>bitset</span>时,而<span>string</span>中的字符不是’<span>0</span>’或’<span>1</span>’的时候,抛出该异常</p></td></tr></tbody></table><p><strong>runtime_error</strong><strong>的子类:</strong></p><table><colgroup><col /><col /></colgroup><tbody><tr><td><p>异常名称</p></td><td><p>描述</p></td></tr><tr><td><p>range_error</p></td><td><p>计算结果超出了有意义的值域范围</p></td></tr><tr><td><p>overflow_error</p></td><td><p>算术计算上溢</p></td></tr><tr><td><p>underflow_error</p></td><td><p>算术计算下溢</p></td></tr><tr><td><p>invalid_argument</p></td><td><p>参数不合适。在标准库中,当利用<span>string</span>对象构造<span>bitset</span>时,而<span>string</span>中的字符不是’<span>0</span>’或’<span>1</span>’的时候,抛出该异常</p></td></tr></tbody></table><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"73f408aa-82cb-407d-b60b-20321037f5b1\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[#include<stdexcept>\nclass Person{\npublic:\n\tPerson(int age){\n\t\tif (age < 0 || age > 150){\n\t\t\tthrow out_of_range(\"年龄应该在0-150岁之间!\");\n\t\t}\n\t}\npublic:\n\tint mAge;\n};\n\nint main(){\n\n\ttry{\n\t\tPerson p(151);\n\t}\n\tcatch (out_of_range& ex){\n\t\tcout << ex.what() << endl;\n\t}\n\t\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><h3><span>7.3.2 </span>编写自己的异常类</h3><p>① 标准库中的异常是有限的;</p><p>② 在自己的异常类中,可以添加自己的信息。(标准库中的异常类值允许设置一个用来描述异常的字符串)。</p><ol><li><strong> </strong><strong>如何编写自己的异常类?</strong></li></ol><p>① 建议自己的异常类要继承标准异常类。因为<span>C++</span>中可以抛出任何类型的异常,所以我们的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开发时。</p><p>② 当继承标准异常类时,应该重载父类的<span>what</span>函数和虚析构函数。</p><p>③ 因为栈展开的过程中,要复制异常类型,那么要根据你在类中添加的成员考虑是否提供自己的复制构造函数。</p><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"3d96c668-8f3e-4df8-97de-f4fcefc27cff\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[//自定义异常类\nclass MyOutOfRange:public exception\n{\npublic:\n\tMyOutOfRange(const string errorInfo)\n\t{\n\t\tthis->m_Error = errorInfo;\n\t}\n\n\tMyOutOfRange(const char * errorInfo)\n\t{\n\t\tthis->m_Error = string( errorInfo);\n\t}\n\n\tvirtual ~MyOutOfRange()\n\t{\n\t\n\t}\n\tvirtual const char * what() const\n\t{\n\t\treturn this->m_Error.c_str() ;\n\t}\n\n\tstring m_Error;\n\n};\n\nclass Person\n{\npublic:\n\tPerson(int age)\n\t{\n\t\tif (age <= 0 || age > 150)\n\t\t{\n\t\t\t//抛出异常 越界\n\t\t\t//cout << \"越界\" << endl;\n\t\t\t//throw out_of_range(\"年龄必须在0~150之间\");\n\n\t\t\t//throw length_error(\"长度异常\");\n\t\t\tthrow MyOutOfRange((\"我的异常 年龄必须在0~150之间\"));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis->m_Age = age;\n\t\t}\n\t\t\n\t}\n\n\tint m_Age;\n};\n\n\nvoid test01()\n{\n\ttry\n\t{\n\t\tPerson p(151);\n\t}\n\tcatch ( out_of_range & e )\n\t{\n\t\tcout << e.what() << endl;\n\t}\n\tcatch (length_error & e)\n\t{\n\t\tcout << e.what() << endl;\n\t}\n\tcatch (MyOutOfRange e)\n\t{\n\t\tcout << e.what() << endl;\n\t}\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/58954474"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954474","edit":"/pages/resumedraft.action?draftId=58954474","tinyui":"/x/6pKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954474"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954474/child","restrictions":"/rest/api/content/58954474/restriction/byOperation","history":"/rest/api/content/58954474/history","ancestors":"","descendants":"/rest/api/content/58954474/descendant","space":"/rest/api/space/2CT"}} |