C++ 派生类成员的标识与访问——虚基类及其派生类构造函数

虚基类的使用非常方便,简单,这是由于程序中所有类使用的都是自动生成的默认构造函数。如果虚基类声明有非默认的(即带参的)构造函数,并且没有声明默认形式的构造函数。这时,在整个继承关系中,直接或者间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化。

【例】

cpp 复制代码
class B0
{
public:
	B0(int v):v0(v){}//非默认构造函数
	int v0;
	void fun0()
	{
		cout << "基类B0的成员" << endl;
	}
};

class B1 :virtual public B0
{
public:
	B1(int v):B0(v){}//非默认构造函数
	int v1;
};

class B2 :virtual public B0
{
public:
	B2(int v) :B0(v) {}//非默认构造函数
	int v2;
};

class D :public B1, public B2
{
public:
	D(int v):B0(v),B1(v),B2(v){}//非默认构造函数
	int v;
	void fun()
	{
		cout << "派生类D的成员" << endl;
	}
};

int main()
{
	D d(1);
	d.v0 = 2;
	d.fun0();
	return 0;
}

运行结果:

分析:

在建立D对象d时,通过D来的构造函数的初始化列表,不仅调用了虚基类的构造函数B0(),对从B0继承的成员v0进行了初始化,而且还调用了直接基类B1和B2的构造函数B1()和B2(),而B1()和B2()的初始化列表中也都有对基类B0的初始化。这样,对于虚基类继承来的v0是否初始化了3次呢?

对于这个问题,我们完全不用担心,C++编译器会处理这个问题。先称建立对象时所指定的类称为当时的最远派生类。在建立一个对象时,如果这个对象中含有从虚基类继承来的成员时,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。而且,只有最远派生类的构造函数会调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用都会被自动忽略。

例如上述代码中的B0是派生类B1和B2的虚基类,主函数中建立的最远派生类D的对象d中含有从虚基类继承来的成员v0,这时,虚基类B0的成员v0是由最远派生类D的构造函数通过调用虚基类B0的构造函数进行初始化的。此时,该派生类D的其他基类B1和B2对虚基类B0的构造函数的调用被自动忽略。

总结:

构造一个类的对象的一般顺:

(1)如果该类有直接或者间接的虚基类,则先执行虚基类中的构造函数。

(2)如果该类有其他基类,则按照它们在继承声明列表中出现的次序,分别执行它们的构造函数,但在构造过程中,不再执行它们的虚基类的构造函数。

(3)按照在类定义中出现的顺序,对派生类中新增的成员对象进行初始化。对于类类型的成员对象,如果出现在构造函数的初始化列表中,则以其中指定的参数执行构造函数,如未出现,则执行默认构造函数;对于基本数据类型的成员对象,如果出现在构造函数的初始化列表中,则使用其中指定的值为其赋初值,否则什么也不做。

(4)执行构造函数函数体。

相关推荐
码匠许师傅几秒前
【C++ 面试真题】20. 聊聊 C++ 的标准库常用算法
c++·算法·面试
Logintern0912 分钟前
什么时候应该用多进程什么时候用多线程呢?
开发语言·python
long31612 分钟前
枚举(Enums)
java·开发语言·数据库
ShiXZ2131 小时前
网络调试四剑客:ping / telnet / nc / netstat 速查指令集
运维·开发语言·网络·php
码农大叔的博客1 小时前
golang示例:switch
开发语言·后端·golang
个 人 练 习 生1 小时前
数据结构入门:算法复杂度
开发语言·数据结构·经验分享·学习·程序人生·算法
白色冰激凌1 小时前
[SECS/GEM研究] (六)SML与数据序列化
c++·secs/gem
W_326001 小时前
Python-OpenCV边缘检测与阈值分割:Sobel、Scharr、Laplacian、Canny、全局与自适应阈值
开发语言·图像处理·python·opencv·机器学习
其实防守也摸鱼1 小时前
红队技能总结导图:从入门到精通的完整知识体系
开发语言·人工智能·学习·安全·web安全
_小柏_1 小时前
总结下最近面试出现的问题
c++·面试