C++中继承

摘要

可以说普通继承是先构造基类再构造派生类，而虚继承将基类嵌入到派生类中只构造一次，以确保虚基类只被构造一次。

当基类的构造函数包含输出语句 "constructor" 时，在虚继承和普通继承的情况下会有不同的输出结果。

考虑以下示例代码：

Copy
#include <iostream>

class Base {
public:
Base() {
std::cout << "constructor" << std::endl;
}
};

class Derived : public virtual Base {
public:
Derived() : Base() {
}
};

int main() {
Derived d;
return 0;
}

在上述代码中，Derived类通过虚继承方式继承了Base类，并在构造函数中调用了基类的构造函数。当我们运行此代码时，会发现只输出一次 "constructor"。这是因为虚继承保证了虚基类（在这里是Base类）只被构造一次，即使在多层继承中也是如此。所以在派生类Derived的构造函数中只会调用一次基类Base的构造函数。

现在考虑使用普通继承的情况：

Copy
#include <iostream>

class Base {
public:
Base() {
std::cout << "constructor" << std::endl;
}
};

class Derived : public Base {
public:
Derived() : Base() {
}
};

int main() {
Derived d;
return 0;
}

在这个例子中，Derived类通过普通继承方式继承了Base类，并在构造函数中调用了基类的构造函数。运行这段代码时，会输出两次 "constructor"，一次来自于基类的构造函数调用，另一次来自派生类的构造函数调用。

因此，虚继承确保虚基类只被构造一次，而普通继承会在每个继承层次中都调用基类的构造函数。这是虚继承与普通继承在构造函数调用方面的一个重要区别。

在虚继承的情况下，一次输出 "constructor" 来自于最终派生类的构造函数调用基类的构造函数。

考虑以下示例代码：

Copy
#include <iostream>

class Base {
public:
Base() {
std::cout << "constructor" << std::endl;
}
};

class Intermediate : public virtual Base {
public:
Intermediate() : Base() {
}
};

class Derived : public Intermediate {
public:
Derived() : Intermediate() {
}
};

int main() {
Derived d;
return 0;
}

在这个例子中，存在一个中间类 Intermediate，它通过虚继承方式继承了 Base 类。派生类 Derived 通过继承 Intermediate 类来间接虚继承 Base 类。

当我们运行这段代码时，只会输出一次 "constructor"。这一次输出来自于最终派生类 Derived 的构造函数调用 Intermediate 类的构造函数，而 Intermediate 类的构造函数又调用了基类 Base 的构造函数。

因此，在虚继承中，一次输出 "constructor" 来自于最终派生类的构造函数调用虚基类的构造函数。这确保了虚基类只被构造一次。

在普通继承中，构造派生类对象时，首先会先构造基类部分，然后在此基础上构造派生类部分。这意味着基类的构造函数会在派生类的构造函数之前被调用。因此，在普通继承中，先构造基类，再构造派生类。

而在虚继承中，基类的构造函数只会被调用一次，无论继承关系的层次有多深。虚继承引入了额外的指针或机制，将虚基类嵌入到派生类中，以确保虚基类只被构造一次。在派生类的构造函数调用链中，最终派生类负责调用虚基类的构造函数，而不是每个派生类都去调用基类的构造函数。

所以，可以说普通继承是先构造基类再构造派生类，而虚继承将基类嵌入到派生类中只构造一次，以确保虚基类只被构造一次。

这种区别是为了解决多重继承中的问题，如菱形继承问题，虚继承的引入使得在多重继承的情况下能够更灵活地管理和初始化基类部分的成员。

所以普通构造相当于先构造一个基类再在此基础上构造派生类？虚继承相当于将基类嵌入派生类只构造一次？

在普通继承中，构造派生类对象时，首先会先构造基类部分，然后在此基础上构造派生类部分。这意味着基类的构造函数会在派生类的构造函数之前被调用。因此，在普通继承中，先构造基类，再构造派生类。

而在虚继承中，基类的构造函数只会被调用一次，无论继承关系的层次有多深。虚继承引入了额外的指针或机制，将虚基类嵌入到派生类中，以确保虚基类只被构造一次。在派生类的构造函数调用链中，最终派生类负责调用虚基类的构造函数，而不是每个派生类都去调用基类的构造函数。

总结

所以，可以说普通继承是先构造基类再构造派生类，而虚继承将基类嵌入到派生类中只构造一次，以确保虚基类只被构造一次。

这种区别是为了解决多重继承中的问题，如菱形继承问题，虚继承的引入使得在多重继承的情况下能够更灵活地管理和初始化基类部分的成员。