Derived构造函数看起来是inlining的绝佳候选人,因为他根本不含任何代码,但是事实可以理解为如下:
Derived::Derived() { // "空白Derived构造函数"的观念性实现 Base::Base(); // 初始化Base成分 try { dm1.std::string::string();// 试图构造dm1 } catch (...) { Base::~Base(); // 如果抛出异常就销毁base class成分,并传播该异常 throw; } try { dm2.std::string::string();// 试图构造dm2 } catch (...) { dm1.std::string::~string();// 如果抛出异常就销毁dm1,销毁base class成分,并传播该异常 Base::~Base(); throw; } try { dm3.std::string::string();// 试图构造dm3 } catch (...) { dm2.std::string::~string(); // 如果抛出异常就销毁dm2,销毁dm1,销毁base class成分,并传播该异常 dm1.std::string::~string(); Base::~Base(); throw; } }以上代码并不能代表编译器真正制造出来的代码,因为现实情况是编译器会以更精致的做法处理异常;Derived构造函数至少一定会陆续调用其成员变量和base class两者的构造函数,如果Base构造函数被inlined,所有替换"Base构造函数调用"而插入的代码也会被插入到"Derived构造函数调用"内;如果string构造函数恰巧也别inlined,则Derived构造函数将获得五份"string 构造函数代码"副本,每一份副本对应于Derived对象的五个字符串(两个来自继承,三个来自自己的声明)之一;
还有一个事实就是大部分调试器对inline函数都束手无策,因为你无法在一个并不存在的函数内打断点调试