专业编程基础技术教程

网站首页 > 基础教程 正文

C++|数据成员的初始化:构造函数初始化列表和函数体

ccvgpt 2024-10-10 05:02:11 基础教程 66 ℃

C++的类除了封装、继承、多态三大特性以外,还可以完成数据成员的构造初始化和动态内存的析构。

我们知道,常量或只读变量只能初始化,此外再没有赋值的机会。所以const成员或引用类型(可以理解为一种由编译器实现了自解引用的指针常量)的成员只能初始化,不能在构造函数体中使用赋值操作。

C++|数据成员的初始化:构造函数初始化列表和函数体

另外,若该类的对象成员类型是没有默认构造函数,则必须进行显示初始化,因为编译器会隐式调用对象成员类型的默认构造函数,而它又没有默认构造函数,则编译器尝试使用默认构造函数将会失败。

当然,对于其它普通成员,可以选择在初始化列表中进行初始化或在构造函数体中进行赋值构造。

另外,在继承关系中,若子类的父类没有默认的构造函数,则在子类的初始化类表中也必须调用父类的一个自定义构造函数。

C++本身就规定创建子类对象的时,先调用基类的构造函数,然后再调用自己类的构造函数。当我们的基类没有自己定义构造函数时候(就是系统默认的构造函数)时。创建子类对象会先默认调用基类的默认构造函数 。但是,当我们的基类自己定义了构造函数,(可能定义了很多个)此时不会再自动生产默认构造。但是它不知道应该调用基类中的哪个构造,所以需要手动指定。(如果基类定义了无参的构造函数,派生类可以不在构造函数的参数列表中调用基类的构造函数)

构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。

#include <iostream>
using namespace std;
class Cb // 无默认构造函数
{
public:
 Cb (int x)
 {
 i = x; 
 }
private:
 int i;
};
class Base
{
	int b;
public:
	Base(int i):b(i){}
};
class Derive:public Base
{
public:
	Derive(int base,int cbi, int cc,int rr,int j) : Base(base),cb(cbi),c(cc),r(rr)
	{
		mvar = j;
	}
private:
 Cb cb;
 int mvar;
	const int c;
 int& r;
};
int main( )
{
	int i = 6;
 Derive(2,3,4,i,5);
 return 0;
}

总结一下,派生类构造函数的语法:

派生类名::派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),…,基类名n(参数表n),对象成员1(参数表1),对象成员名2(参数表2),…,对象成员名n(参数表n),const对象成员(参数),引用数据成员(参数)

{

派生类新增普通成员的赋值初始化;

}

对象成员也就是内嵌子对象(或组合对象)。基类或对象成员如果有定义默认构造函数,可以不在初始化列表中初始化,会调用默认的构造函数(没有定义构造函数时,编译器会自动生成一个默认构造函数,当然也可以自定义一个默认构造函数)。

显然利用初始化列表可以提高构造函数的效率。在初始化的时候,同时完成了赋初始的工作。

构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数。析构则严格按照与构造相反的次序执行, 该次序是唯一的,否则编译器将无法自动执行析构过程。

一 个有趣的现象是,成员对象初始化的次序完全不受它们在初始化表中次序的影响,只由成员对象在类中声明的次序决定。这是因为类的声明是唯一的, 而类的构造函 数可以有多个,因此会有多个不同次序的初始化表。如果成员对象按照初始化表的次序进行构造,这将导致析构函数无法得到唯一的逆序。

-End-

最近发表
标签列表