C++知识点49——类继承与类的构造、拷贝、operator=和析构函数

一、类继承与构造函数

在C++中,无论类是否有继承关系,每个类各自控制它自己的成员的初始化。子类虽然含有基类的成员,但是并不能对基类的成员直接初始化,需要使用基类的构造函数初始化子类中的基类部分。

从语法上说,可以在子类的构造函数的函数体中给基类的protected或public成员赋值,但是最好不要这样做

子类初始化时,会先调用基类的构造函数,初始化基类的部分并,然后按照子类成员在类中的声明顺序逐个初始化子类部分

示例

class base
{
public:
	base():
	bpub(0),
	bpro(0),
	bpri(0)
	{
		cout<<__func__<<endl;
	}

	base(int init):
	bpub(0),
	bpro(0),
	bpri(0)
	{
		cout<<"base(int init)"<<endl;
	}

	~base(){cout<<__func__<<endl;}
	int bpub; 

protected:
	int bpro;

private:
	int bpri;
	
};

class derive:public base
{
public:
	derive(){cout<<__func__<<endl;}
	~derive(){cout<<__func__<<endl;}
	int dpub; 

protected:
	int dpro;

private:
	int dpri;
	
};

class derive2:public base
{
public:
	derive2():
	base(),
	d2pub(-1),
	d2pro(-1),
	d2pri(-1)
	{
		cout<<__func__<<endl;
	}

	derive2(int init):
	base(init),
	d2pub(-1),
	d2pro(-1),
	d2pri(-1)
	{
		cout<<"derive2(int init)"<<endl;
	}

	~derive2() 
	{
		cout<<__func__<<endl;
	}

	int d2pub; 

protected:
	int d2pro;

private:
	int d2pri;
};

int main(int argc, char const *argv[])
{
	derive d;
	derive2 d21;
	derive2 d22(10);
	return 0;
}

上述代码演示了如何在子类的构造函数中显示指定要调用基类的构造函数

输出结果表示:

1、就算在子类的构造函数中不显式指定调用基类的构造函数,当创建子类对象(derive)时,会先调用基类的默认构造函数并对基类部分进行默认初始化。

2、定义类时,可以将子类构造函数的形参传给基类的构造函数

 

二、类继承与拷贝构造函数

如果想在拷贝子类对象时,对基类的成员也进行拷贝,需要在子类的拷贝构造函数的初始化列表中显示调用基类的拷贝构造函数。如果不显示定义基类的拷贝构造函数,那么在对子类进行拷贝构造操作时,会先调用基类的构造函数

示例

class base2
{
public:
	base2(){cout<<__func__<<endl;}
	base2(const base2 &b2):memb(b2.memb){cout<<"base2(const base2 &b2)"<<endl;}
	~base2(){cout<<__func__<<endl;}
	int memb;
};

class derive2:public base2
{
public:
	derive2(){cout<<__func__<<endl;}
	~derive2(){cout<<__func__<<endl;}
	derive2(const derive2 &d2)
	:base2(d2), memd(d2.memd) {cout<<"derive2(const derive2 &d2)"<<endl;}
	int memd;
};

int main(int argc, char const *argv[])
{
	derive2 d2;
	derive2 b2t=d2;
	return 0;
}

如果想在拷贝子类对象时,对基类的成员也进行拷贝,需要在子类的拷贝构造函数的初始化列表中显示调用基类的拷贝构造函数。这样,当对一个子类进行拷贝初始化时,也会先调用基类的拷贝构造函数,对子类中的基类部分进行拷贝初始化,然后再调用子类的拷贝构造函数进行对子类部分进行拷贝初始化

如果不显示调用基类的拷贝构造函数,那么在对子类进行拷贝构造操作时,会先调用基类的构造函数,将上述代码中的第5行注释掉的输出结果如下

所以,如果要定义子类的拷贝构造函数,请在子类的拷贝构造函数的初始化列表中显示调用基类的拷贝构造函数,然后再对子类的成员进行初始化

如果没有显式定义子类的拷贝构造函数,那么一般情况下,编译器会默认生成一个,此时对子类对象进行拷贝初始化也会调用基类的拷贝构造函数

 

三、类继承与operator=

和拷贝构造函数一样,子类的operator=必须显示调用基类的operator=

示例

在拷贝构造函数的示例代码中分别添加基类和子类的operator=

class base2
{
public:
	//....
	base2 &operator=(const base2 &b2)
	{
		memb=b2.memb;
		return *this;
	}
	int memb;
};

class derive2:public base2
{
public:
	//....
	derive2 &operator=(const derive2 &d2)
	{
		base2::operator=(d2);
		memd=d2.memd;
		return *this;
	}
	int memd;
};

int main(int argc, char const *argv[])
{
	derive2 d2;
	derive2 b2t;
	b2t=d2;
	return 0;
}

如果不显示调用基类的operator=,那么子类对象的基类部分将不会被赋值

如果子类没有显示定义operator=,那么编译器一般情况会默认生成一个operator=,此时对子类对象进行赋值时,会调用基类的operator=

 

四、类继承与析构函数

根据上面的输出结果可以知道,对象销毁的顺序和对象创建的顺序是相反的,一个子类对象销毁时,会先执行子类的析构函数,然后是基类的析构函数,以此类推,直至最上面的基类

虽然子类对象被释放时,会分别调用子类和基类的析构函数,但是,子类的析构函数只负责释放子类的成员所占有的资源,子类中对应的基类部分由基类的析构函数进行释放

 

参考

《C++ Primer》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值