MST

星途 面试题库

面试题:C++ 多重继承下构造函数与析构函数调用顺序及内存布局

考虑以下 C++ 多重继承的代码: ```cpp class A { public: A() { std::cout << "A constructor" << std::endl; } ~A() { std::cout << "A destructor" << std::endl; } }; class B { public: B() { std::cout << "B constructor" << std::endl; } ~B() { std::cout << "B destructor" << std::endl; } }; class C : public A, public B { public: C() { std::cout << "C constructor" << std::endl; } ~C() { std::cout << "C destructor" << std::endl; } }; ``` 1. 写出 `C c;` 这条语句执行时构造函数和析构函数的调用顺序,并说明理由。 2. 简单描述 `C` 类对象在内存中的布局情况。
14.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 构造函数和析构函数调用顺序及理由
    • 构造函数调用顺序
      • 首先调用 A 的构造函数,因为在 C 类继承列表中 A 在前。A 类是 C 类的第一个直接基类,根据 C++ 规则,在创建派生类对象时,先调用基类的构造函数。所以会输出 “A constructor”。
      • 接着调用 B 的构造函数,BC 类的第二个直接基类,输出 “B constructor”。
      • 最后调用 C 自身的构造函数,输出 “C constructor”。
      • 所以构造函数调用顺序为:A constructor -> B constructor -> C constructor。
    • 析构函数调用顺序
      • 与构造函数调用顺序相反。当 C 对象生命周期结束时,先调用 C 自身的析构函数,输出 “C destructor”。
      • 然后调用 B 的析构函数,因为 B 是第二个被构造的基类,输出 “B destructor”。
      • 最后调用 A 的析构函数,输出 “A destructor”。
      • 所以析构函数调用顺序为:C destructor -> B destructor -> A destructor。
  2. C 类对象在内存中的布局情况
    • 内存布局中,首先是 A 类对象的部分,包含 A 类的数据成员(本题中 A 类无数据成员)和虚函数表指针(如果 A 类有虚函数)。
    • 接着是 B 类对象的部分,同样包含 B 类的数据成员(本题 B 类无数据成员)和虚函数表指针(如果 B 类有虚函数)。
    • 最后是 C 类自身的数据成员(本题 C 类无数据成员)和虚函数表指针(如果 C 类有虚函数)。这种布局使得 C 类对象能够完整地包含 AB 类的所有信息,并且可以通过合适的偏移量访问不同部分的数据和函数。