Bootstrap

C++ 【类和对象: 析构函数,拷贝构造函数,运算符重载 --2】

目录

1.默认(缺省)成员函数:析构函数

当带有static时,析构和构造函数的创建/销毁顺序是?

在成员函数中调用delete this会出现什么问题?对象还可以使用吗?

如果在类的析构函数中调用delete this,会发生什么?

2.拷贝构造函数

2.1 内置类型和自定义类型

3.运算符重载

前置++和后置++重载

 3.3.友元

4.赋值运算符重载:=

5.const成员

6.取地址及const取地址操作符重载


1.默认(缺省)成员函数:析构函数

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作由编译器完成

对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

析构函数特性

1. 析构函数名是在类名前加上字符 ~

2. 无参数无返回值类型

3.一个类只能有一个析构函数。若未定义,系统会自动生成默认的析构函数。析构函数不能重载

4.对象生命周期结束,C++自动调用析构函数

5.手动开辟的例如Stack中malloc,fopen等需要析构函数,Date日期类不需要析构函数

6.编译器生成的默认析构函数,对内置类型不做处理,对自定类型成员调用它的析构函数

7.析构函数可以定义在类外

	~Stack()
	{
		free(...);
	}

析构函数顺序

先定义的先构造,后定义后构造; 先定义的后析构,后定义的先析构(栈和栈帧里面的对象都要符合后进先出)

class A
{
public:
	A(int a = 0)
	{
      _a = a;
		cout << "A(int a = 0)->" <<_a<< endl;
	}

	~A()
	{
		cout << "~A()->" <<_a<<endl;
	}
private:
	int _a;
};


void f()
{
	A aa1(1);
	A aa2(2);
}

int main()
{
	f();
	return 0;
}

当带有static时,析构和构造函数的创建/销毁顺序是?

两个局部静态对象,一个全局对象

class A
{
public:
	A(int a = 0)
	{
      _a = a;
		cout << "A(int a = 0)->" <<_a<< endl;
	}

	~A()
	{
		cout << "~A()->" <<_a<<endl;
	}
private:
	int _a;
};

A aa3(3);

void f()
{
	static A aa4(4);
	A aa1(1);
	A aa2(2);
    static A aa5(5);
}

int main()
{
	f();
	return 0;
}

全局变量最先被初始化(main函数之前初始化,全局和静态都在静态区),局部静态特点是第一次运行后初始化

析构是aa2和aa1中最先析构,原因在于剩余三个生命周期在程序结束后才销毁,main函数栈帧结束清理在栈帧中的aa2和aa1;main函数结束,再调用全局和静态(符合先定义后析构)

 如果调用两次f()函数,结果又是如何?

 

静态变量在第一次执行后初始化,第一次函数调用结束,aa4和aa5不会销毁

在成员函数中调用delete this会出现什么问题?对象还可以使用吗?

在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内容,类的成员函数单独放 在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。 当调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题。

为什么是不可预期的问题?

delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个进程。照这个逻辑来看,应该发生野指针之类的令崩溃的问题。这个问题牵涉到操作系统的内存管理策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当你获取数据成员,可能得到的是未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。

如果在类的析构函数中调用delete this,会发生什么?

会导致堆栈溢出。delete的本质是“为将被释放的内存调用一个或多个析构函数,然后,释放内存”。显然,delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成堆栈溢出,系统崩溃。


2.拷贝构造函数

有时候我们需要对一个对象进行拷贝,就会调用拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

int main()
{
	Date d1(2022, 7, 31);
	Date d2(d1);//拷贝构造两个写法
    Date d3 = d1;
	return 0;
}

;