C++ 构造函数和析构函数

文章详细介绍了C++中的构造函数,包括它们的作用、形式、调用时机,以及默认构造函数、重载、带默认值参数的情况。还讨论了复制构造函数的用途和调用场景,并提到了左值和右值的概念,以及移动构造函数的基本思想。
摘要由CSDN通过智能技术生成

构造函数

含义:在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态


构造函数的形式:

1.函数名与类名相同
2.不能定义返回值类型,不能有return语句
3.可以有形式参数,也可以没有
4.可以是内联参数
5.可以重载
6.可以带默认值参数

构造函数的调用时机:

对象创建时自动调用,例如Clock myClock(0,0,0);
不写构造函数时由编译器调用默认构造函数(隐含生成的构造函数):
  • 参数列表为空,不为数据成员设置初始值
  • 如果类内定义了成员的初始值,则使用类内定义的初始值
  • 如果类内没有定义成员的初始值,则以默认方式初始化
  • 基本类型的数据默认初始化是不确定的

默认构造函数:

调用时可以不需要实参的构造函数:
  • 参数表为空
  • 全部参数都有默认值
  • 下面两个都是默认构造函数,如果在类内同时出现会报错:
Clock();
Clock(int newH=0,int newM=0,int newS=0);
//两个默认构造函数不是重载形式的
class Clock{
	public:
	Clock(int newH,int newM,int newS);
	//构造函数,写该函数后就不自动生成默认构造函数,如果要在主函数中使用默认构造函数
	//则需要自己定义一个默认构造函数
	Clock();//默认构造函数
	void setTime(int newH,int newM,int newS);
	void showTime();
	private:
	int hour,minute,second;
}

Clock::Clock(int newH,int newM,int newS):hour(newH),minute(newM),second(newS){
}
//构造函数的实现,这种形式运行效率更高
/*构造函数的另一种实现方式,将初始化语句写在函数体内,这样可以在函数体内实现24与12小时制的转换
Clock::Clock(int newH,int newM,int newS){
	hour=newH;
	minute=newM;
	second=newS;
}*/
Clock::Clock():hour(0),minute(0),second(0){
}
//默认构造函数的实现

int main(){
	Clock c(0,0,0);//自动调用构造函数
	c.showTime();
	return 0;
}

“=default”

如果类中已定义构造函数,此时仍希望编译器生成默认构造函数,可以使用=defalut
class Clock{
	public:
		Clock()=defalut;//指示编译器提供默认构造函数
		Clock(int newH,int newM,int newS);
	private:
		int hour,minute,second;
}
  • default的作用是如果主函数中创建对象时都给了参数,也就是不需要默认构造函数,那默认构造函数在整个程序运行中就不生成,一旦存在一个对象创建时没给函数,此时就会生成默认构造函数,与Clock();的区别是Clock();这个默认构造函数在整个程序运行中都是存在的,因此default一定程度上可以节约空间

委托构造函数:

含义:类中往往有多个构造函数,只是参数表和初始化列表不同,其初始化算法都是相同的,这时为了避免代码重复,可以使用委托构造函数

委托构造函数使用类的其他构造函数执行初始化过程
/*Clock::Clock(int newH,int newM,int newS):hour(newH),minute(newM),second(newS){}
  Clock::Clock():hour(0),minute(0),second(0){}
  可以合并为下面代码
*/
Clock::Clock():Clock(0,0,0){}

复制构造函数:

1.我们经常会需要用到一个已经存在的对象去初始化一个新的对象,类似于int a=1,int b=a,这时就需要复制构造函数

2.隐含生成的复制构造函数可以实现对应数据成员一一复制

3.自定义的复制构造函数可以实现特殊的复制功能

定义:

复制构造函数是一种特殊的构造函数,其形参为本类的对象引用,作用是用一个已存在的对象去初始化同类型的对象

class 类名{
	public:
	类名(形参);//构造函数
	类名 (const 类名 &对象名);//复制构造函数
	...
}
类名::(const 类名 &对象名){函数体}//复制构造函数的实现

“=delete”

如果要求一个类中的对象相互之间不能通过复制来赋值,也就是不允许复制,那么可以用=delete指示编译器不生成默认复制构造函数
class Point{
	public:
		Point(int xx=0,int yy=0){x=xx;y=yy;}//构造函数,内联
		Point(const Point &p)=delete;
		/*指示编译器不生成默认复制构造函数*/
	private:
		int x,y; 
}

复制构造函数被调用的三种情况:

1.定义一个对象时,以本类另一个对象作为初始值,发生复制构造
2.如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造
3.如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象,传递给主调函数,发生复制构造

在这里插入图片描述

class Point{
	public:
		Point(int xx=0,int yy=0){x=xx;y=yy;}//构造函数,内联
		Point(const Point &p);//复制构造函数
		void setX(int xx){x=xx;}
		void setY(int yy){y=yy;}
		int getX() const{return x;}
		int getY() const{return y;}
	private:
		int x,y; 
}

Point::Point(const Point &p){//复制构造函数的实现
	x=p.x;
	y=p.y;
	cout<<"Calling the copy constructor"<<endl;
}

左值和右值:

  • 左值是位于赋值运算左侧的对象或变量,右值是位于赋值运算右侧的值

左值引用和右值引用:

  • 对持久存在变量的引用称为左值引用,用&表示
  • 对短暂存在可被移动的右值的引用称为右值引用,用&&表示
  • 这里的&不是地址符
float n=6;
float &lr_n=n;//左值引用
float &&rr_n=n;//错误,右值引用不能绑定到左值
float &&rr_n=n*n;//正确,右值表达式绑定到右值引用
  • 通过标准库< utility >中的move函数可将左值对象移动为右值
float n=10;
float &&rr_n=std::move(n);//将左值转化为右值
//使用move函数承诺除对n重新赋值或销毁外,不以rr_n以外方式使用

移动构造函数(了解即可):

基于右值引用,移动构造函数通过移动数据方式构造对象,与复制构造函数类似,移动构造函数参数为该类对象的右值引用,区别在于复制后是两个对象,移动后新对象存在,旧对象消失

#include<utility>
class astring
	public:
		std::string s;
		astring(astring&& o)noexcept:s(std::move(o.s))//显示移动所有成语
		{函数体}
  • 移动构造函数不分配新内存,理论上不会报错,为配合异常捕获机制,需声明noexcept表面不会抛出异常
  • 被移动的对象不应再使用,需要销毁或重新赋值

析构函数

  • 完成对象被删除前的一些清理工作
  • 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间
  • 如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数,其函数体为空
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值