C++基础---构造函数和析构函数

对象的初始化和清理

构造函数–初始化

析构函数–清理

编译器自动调用,创建对象时,编译器自动调用构造函数,对象销毁时,编译器自动调用析构函数

默认情况下,C++会给一个类默认添加三个函数

  1. 默认构造函数,函数体为空
  2. 默认析构函数,函数体为空
  3. 默认复制构造函数,对属性进行值拷贝
1 构造函数
class Point
{
private:
	int p_x,p_y;
public:
	Point(int x, int y):p_x(x),p_y(y) //自定义构造函数,初始化列表
	{
	}
};

语法:

  • 没有返回值,并且不写void
  • 函数名和类名相同
  • 构造函数只在创建时调用一次,且无需手动调用
  • 构造函数可以有参数,可以重载

特别注意

  • 如果程序员没有自定义构造函数,编译器会调用默认该构造函数,即为空函数
  • 一旦程序员自定义了构造函数,C++不再提供无参默认构造函数,但还是会提供默认复制构造函数
  • 一旦程序员自定义了复制构造函数,C++不再提供普通构造函数

调用:

Point p1(0,9);//方式一
Point p2 = Point(0,9);//方式二
Point p3 = (0,9); //方式三

构造函数的分类:

按照有无参数:有参构造函数和无参构造函数

按照类型分类:普通构造函数和复制构造函数

1.1 有参构造函数和无参构造函数

无参构造函数也称作默认构造函数

有参构造函数一般用作成员变量初始化工作

1.2 普通构造函数和复制构造函数

复制构造函数

实现:

Point(const Point &p)
{
	p_x = p.p_x;
	p_y = p.p_y;
}

除复制构造函数之外的都称作普通构造函数

调用:

Point p1(0,9);
Point p2(p1); //p2从p1中复制其成员变量进行初始化赋值
Point p3 = Point(p1);//方式二
Point p4 = p3;//方式三,
Point(10);//匿名对象,特点:当前行执行结束后,系统会立即回收

以下三种情况下会调用复制构造函数:

  • 使用一个已创建的对象来初始化一个新对象
  • 值传递的形式给函数形参传值
  • 值的方式返回局部变量,即函数返回值为一个对象

浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

下面举个例子来说明浅拷贝带来的问题,以下为出错代码:

#include <iostream>
using namespace std;
class Point
{
public:
	int p_x,p_y;
	int *p_z;
	Point() 
	{
		cout<<"Point的无参默认构造函数调用"<<endl; 
	}
	Point(int x, int y, int z):p_x(x),p_y(y) 
	{
		p_z = new int(z);
		cout<<"Point的有参构造函数调用"<<endl; 
	}
	~Point() 
	{
		if(p_z)  //当成员变量中有指针是,对象消亡时调用析构函数,释放堆区该指针空间 
		{
			delete  p_z;
			p_z = NULL;
		} 
		cout<<"Point的析构函数调用"<<endl; 
	}
	
};

void func01()
{
	Point p1(10,0,2);
	cout<<"("<<p1.p_x<<","<<p1.p_y<<","<<*(p1.p_z)<<")"<<endl; 
	/*若调用编译器提供的默认拷贝构造函数会做一个浅拷贝,即p2的p_z直接拷贝的p1的 p_z,即指向同一内存空间 
	当p2消亡时,析构函数第一次调用时已经释放p_z空间,
	后p1消亡时,再次调用析构函数,会造成堆区内存重复释放 */ 
	Point p2(p1);
	cout<<"("<<p2.p_x<<","<<p2.p_y<<","<<*(p2.p_z)<<")"<<endl;
 } 
int main()
{
	func01();
	system("pause");
	return 0;
}

解决方案:

用深拷贝解决浅拷贝的问题,自定义复制构造函数

Point(const Point &p) 
{
	cout<<"Point的复制构造函数调用"<<endl;
	p_x = p.p_x; p_y = p.p_y;
	p_z = new int(*p.p_z);
}

输出:

Point的有参构造函数调用
(10,0,2)
Point的复制构造函数调用
(10,0,2)
Point的析构函数调用
Point的析构函数调用
2 析构函数

语法:

  • 没有返回值,并且不写void
  • 函数名和类名相同,在函数名前加"~"
  • 析构函数只在对象销毁时调用一次,且无需手动调用
  • 析构函数没有参数,不可以重载
  • 如果程序员没有自定义析构函数,编译器会调用默认该析构函数,即为空函数

类对象作为类成员
class Circle
{
Point p;//Point是另一个已声明的类
int c_r;
}

当创建一个Circle对象时,构造函数和析构函数的调用顺序:

  1. 调用Point构造函数
  2. 调用Circle构造函数
  3. 调用Circle析构函数
  4. 调用Point析构函数

构造的顺序是先构造成员对象的构造,再构造自身,析构的顺序与之相反

3 静态成员

在类成员前加上static关键字,即称为静态成员,静态成员分为静态成员变量和静态成员函数

静态成员变量:

  • 为所有对象所公有
  • 在编译阶段分配内存
  • 类内声明,类外初始化

静态成员函数:

  • 只能访问静态成员,静态成员函数类似全局函数
  • 为所有对象所公有

类外不能访问私有静态成员函数。
调用:

//1.通过对象进行访问
Point p;
p.func();//func是一个静态成员函数
//2.通过类名进行访问
Point::func();
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值