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

相关推荐
愈努力俞幸运21 分钟前
c++ 头文件
开发语言·c++
永日4567027 分钟前
学习日记-day24-6.8
开发语言·学习·php
BillKu27 分钟前
Java后端检查空条件查询
java·开发语言
~山有木兮32 分钟前
C++设计模式 - 单例模式
c++·单例模式·设计模式
十五年专注C++开发1 小时前
CMake基础:gcc/g++编译选项详解
开发语言·c++·gcc·g++
vortex51 小时前
探索 Shell:选择适合你的命令行利器 bash, zsh, fish, dash, sh...
linux·开发语言·bash·shell·dash
zzc9211 小时前
MATLAB仿真生成无线通信网络拓扑推理数据集
开发语言·网络·数据库·人工智能·python·深度学习·matlab
HUN金克斯1 小时前
C++/C函数
c语言·开发语言·c++
慢半拍iii1 小时前
数据结构——F/图
c语言·开发语言·数据结构·c++
钢铁男儿1 小时前
C# 表达式和运算符(表达式和字面量)
开发语言·c#