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)执行构造函数函数体。

相关推荐
李游Leo几秒前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
开发语言·c++·3d·harmonyos
时间的拾荒人39 分钟前
Qt 文件操作详解:从基础类到读写实战
开发语言·qt·面试
Wang's Blog1 小时前
Java 项目实战: 外卖平台优化-YApi接口管理平台与文档导入导出
java·开发语言·yapi
jimy11 小时前
基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的
开发语言·c++
迅猛龙办公室1 小时前
python获取星期字符串
开发语言·python
xlq223221 小时前
全面复习2
c++
无名猿1 小时前
移动构造与移动赋值:把资源偷过来
c++·性能优化·内存管理·现代c++·语法基础
泡海椒2 小时前
JQuick-Excel dateFormat 转换实战:日期值与 FORMAT 显示格式的边界
开发语言·python·excel
All for pursuit.2 小时前
【回溯-7】494.目标和
数据结构·c++·算法·leetcode
白杨尚青2 小时前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl