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

相关推荐
Momentary_SixthSense21 分钟前
serde
开发语言·rust·json
MediaTea27 分钟前
Python 文件操作:JSON 格式
开发语言·windows·python·json
2501_9307077833 分钟前
使用C#代码添加或删除PPT页面
开发语言·c#·powerpoint
攒钱植发36 分钟前
嵌入式Linux——解密 ARM 性能优化:LDR 未命中时,为何 STR 还能“插队”?
linux·arm开发·c++·性能优化
百锦再41 分钟前
金仓数据库提出“三低一平”的迁移理念
开发语言·数据库·后端·python·rust·eclipse·pygame
茉莉玫瑰花茶1 小时前
从零搭建 C++ 在线五子棋对战项目:从环境到上线,全流程保姆级教程
开发语言·c++
卡卡酷卡BUG1 小时前
2025年Java面试题及详细解答(MySQL篇)
java·开发语言·mysql
野生工程师1 小时前
【Python爬虫基础-1】爬虫开发基础
开发语言·爬虫·python
wuwu_q1 小时前
彻底讲清楚 Kotlin 的 when 表达式
android·开发语言·kotlin
一匹电信狗1 小时前
【C++】哈希表详解(开放定址法+哈希桶)
服务器·c++·leetcode·小程序·stl·哈希算法·散列表