构造函数和析构函数的调用顺序

构造函数和析构函数

构造函数

构造函数是特殊的成员函数,与类同名,没有返回类型,而且允许重载。如果没有为类显式定义任何构造函数,编译器将自动为类生成默认构造函数(不带任何参数)。

复制构造函数

复制构造函数、赋值操作符合析构函数总称为复制控制。复制构造函数只有单个形参,而且该形参是对本类类型的引用(通常用const修饰)。复制构造函数常用于:
1)根据另一个同类型的对象初始化一个对象

string a("123456");
string b(a);

2)在顺序容器的元素初始化和类类型数组元素初始化时,也会默认使用复制构造函数。
3)复制一个对象,将它作为实参传给一个函数或从函数返回时复制一个对象。也就是说,如果函数的形参或返回值是一个类的话,将会调用复制构造函数进行复制。

class Myclass
{
public:
	Myclass(int n) { number = n; }
	Myclass(const Myclass &other)
	{
		number = other.number;
		cout << "copy";
	}
private:
	int number;
};

Myclass fun(Myclass p)
{
	Myclass temp(p);
	return temp;
}


void main()
{

	Myclass a(10);
	Myclass b(a);
	Myclass c = fun(b);
	system("pause");
}

最后会输出四个copy,第一次调用在b(a),第二次在fun传参,调用复制构造函数,等价于p(b),第三次temp§,第四次返回值,等价于c(temp)。

析构函数

析构函数用于释放对象在生命期内获取的资源,不管类是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数。需要注意的是,构造函数不能被定义成虚函数,但是析构函数可以。一般来说,如果类中定义了虚函数,那么析构函数也应该被定义成虚函数。虚析构函数和析构函数的差别在于,如果用new运算符建立的派生类的临时对象,对指向基类的指针指向这个临时对象当用delete运算符撤销对象时,系统执行的是基类的析构函数,而不是派生类的析构函数,不能彻底的“清理现场”。解决的方法是将基类及派生类的析构函数设为虚函数,这时无论基类指针指向哪个派生类对象,系统会采用动态关联,调用相应的析构函数对对象进行清理。

class A {
public:
	A() { cout << "A"; }
	~A() { cout << "~A"; }
};
class B: public A{
public:
	B() { cout << "B"; }
	~B() { cout << "~B"; }
};

void f()
{
	A *a = new B;
	delete a;
	getchar();
}
int  main()
{
	f();
	system("pause");
	return 0;
}

此时输出为AB~A,会出现释放不彻底的问题
如果将其均改为虚析构函数(实际这里改A就行),输出就为AB~B ~A

构造函数与析构函数的调用顺序

单继承

派生时,构造函数和析构函数是不能继承的,因此必须在派生类中重新定义构造函数和析构函数。创建派生类时,先调用基类的构造函数完成基类成员的初始化,而后对派生类新增的成员初始化。析构时顺序相反。

class A {
public:
	A() { cout << "A"; }
	A(const A &a) { cout << "copy"; }
	virtual ~A() { cout << "~A"; }

};
class B: public A{
public:
	B(A &a):_a(a) { cout << "B"; }
	virtual ~B() { cout << "~B"; }
private:
	A _a;
};

void f()
{
	A(a);
	B b(a);
}
int  main()
{
	f();
	system("pause");
	return 0;
}

输出为
A A copy B ~B ~A ~A ~A
构造B时,首先调用基类的构造函数,完成初始化,之后调用B的构造函数,此处为复制构造,复制构造函数也会构造一个A对象,复制构造结束后才会构造一个派生类对象。析构时按相反的顺序析构,注意无论是默认构造函数,复制构造函数或者其他重载的构造函数创造的对象,都会被析构。
严格来说,派生类函数的调用顺序为
1)完成对象所占整块内存的开辟,由系统调用构造函数自动完成
2)调用基类的构造函数完成基类成员的初始化
3)派生类中含对象成员,const成员和引用成员的初始化
4)派生类构造函数

多继承

多继承时,按照基类构造函数在类派生列表中的出现次序调用

class A
{
public:
	A() { cout << "A Constructor..." << endl; }
	~A() { cout << "A Destructor..." << endl; }
};

class B
{
public:
	B() { cout << "B Constructor..." << endl; }
	~B() { cout << "B Destructor..." << endl; }
};

class C :public A, public B
{
public:
	C() { cout << "C Constructor..." << endl; }
	~C() { cout << "C Destructor..." << endl; }
};


class D : public C
{
public:
	D() { cout << "D Donstructor..." << endl; }
	~D() { cout << "D Destructor..." << endl; }
};

void f()
{
	D d;
}

void main()
{
	f();
	system("pause");
}

在这里插入图片描述
需要注意的是,如果多继承中存在虚继承,那么优先调用虚继承的构造函数。

发布了97 篇原创文章 · 获赞 114 · 访问量 26万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览