MST

星途 面试题库

面试题:C++ 类继承体系下构造函数重载与调用顺序

定义一个类 `A`,具有多个重载的构造函数。再定义一个类 `B` 继承自 `A`,`B` 也有多个重载的构造函数。在 `main` 函数中创建 `B` 类的对象,分析并阐述在不同构造函数组合调用下,`A` 和 `B` 类构造函数的调用顺序,以及涉及到成员初始化列表时的具体情况。
45.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 构造函数调用顺序

当创建 B 类的对象时,无论 B 类使用哪个重载的构造函数,总是先调用 A 类的构造函数,然后再调用 B 类自身的构造函数。这是因为在创建子类对象时,需要先初始化父类部分,然后再初始化子类特有的部分。

2. 成员初始化列表情况

  • 父类构造函数选择:如果 B 类的构造函数在成员初始化列表中没有显式调用 A 类的特定构造函数,那么编译器会尝试调用 A 类的默认构造函数(如果存在)。如果 A 类没有默认构造函数,编译器会报错。
  • 显式调用父类构造函数:如果 B 类的构造函数在成员初始化列表中显式调用 A 类的某个重载构造函数,那么就会调用该指定的 A 类构造函数。例如:
class A {
public:
    A() {
        std::cout << "A default constructor" << std::endl;
    }
    A(int num) {
        std::cout << "A constructor with int: " << num << std::endl;
    }
};

class B : public A {
public:
    B() : A() {
        std::cout << "B default constructor" << std::endl;
    }
    B(int num) : A(num) {
        std::cout << "B constructor with int" << std::endl;
    }
};

int main() {
    B b1;
    B b2(10);
    return 0;
}

在上述代码中:

  • B b1; 会先调用 A 类的默认构造函数,再调用 B 类的默认构造函数。

  • B b2(10); 会先调用 A 类带 int 参数的构造函数,再调用 B 类带 int 参数的构造函数。

  • 成员初始化顺序:在 B 类构造函数的成员初始化列表中,除了调用父类构造函数外,还会按照成员变量在类中声明的顺序进行初始化,而不是按照成员初始化列表中出现的顺序。例如:

class B : public A {
private:
    int a;
    int b;
public:
    B(int num) : b(num), a(b + 1) {
        std::cout << "B constructor with int" << std::endl;
    }
};

这里虽然在成员初始化列表中先写了 b(num),后写了 a(b + 1),但实际上会先初始化 a(因为 a 先声明),此时 b 还未初始化,所以 a 的初始化值是未定义的。为避免这种情况,应按照声明顺序初始化成员变量。