小言_互联网的博客

C++ 类的6个默认成员函数(构造函数,析构函数,拷贝构造函数,赋值重载函数,取地址及const取地址操作符重载)

570人阅读  评论(0)


1. 类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。空类中什么都没有吗?并不是,任何一个类在我们不写的情况下,都会自动生成下面6个默认的成员函数

2. 构造函数

2.1 前言

仔细观察如下代码:

#include<iostream>
using namespace std;
class Test
{
   
public:
	void GetData()
	{
   
		m_data = 0;
	}
private:
	int m_data;
};
int main()
{
   
	Test t;
	t.GetData();

	return 0;
}

    我们可以看出,对于Test类,我们可以通过GetData公有方法给对象设置内容,但如果每次创建对象都调用该方法设置信息,未免有点麻烦,那能否在对象创建时就将信息设置进去呢?

    面对这种情况构造函数就返回了其作用

2.2 什么是构造函数

构造函数:是一个特殊的成员函数,名字与类名相同,创建对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次(针对一个对象)

如下代码中Test()就是一个构造函数:

#include<iostream>
using namespace std;
class Test
{
   
public:
	Test()
	{
   
		m_data = 0;
	}
private:
	int m_data;
};
int main()
{
   
	Test t;

	return 0;
}

2.3 构造函数的特性

构造函数虽然名称叫构造,但需要注意的是构造函数的主要任务并不是开空间创造对象,而是初始化对象

  • 函数名和类名相同
  • 无返回值
  • 对象实例化时编译器自动调用对应的构造函数
  • 构造函数可以重载

测试如下:

#include<iostream>
using namespace std;
class Test
{
   
public:
	//无参构造函数
	Test()
	{
   }
	//带参构造函数
	Test(int data)
	{
   
		m_data = data;
	}
private:
	int m_data;
};
int main()
{
   
	//调用无参构造函数
	Test t1;
	//调用带参构造函数
	Test t2(20);
	return 0;
}

注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明

  • 如果类中没有定义构造函数,则编译器会自动生成一个无参的默认构造函数,若用户定义构造函数编译器将不再生成
  • 无参构造函数和全缺省构造函数都称为默认构造函数,并且默认构造函数只能有一个

3. 析构函数

3.1 前言

    前面我们通过构造函数的学习,知道了一个对象的怎么来的,那么一个对象又是怎么没的呢?

    于是我们引出了析构函数

3.2 析构函数

析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。

如下代码中~Test()就是一个析构函数

#include<iostream>
using namespace std;
class Test
{
   
public:
	Test(int data)
	{
   
		m_data = data;
		cout << "Creat Test Obj" << endl;
	}
	~Test()
	{
   
		cout << "Free Test Obj" << endl;
	}
private:
	int m_data;
};
int main()
{
   
	Test t(20);
	return 0;
}

运行程序我们会看到,有构造就会有销毁,系统会自动调用析构函数

3.3 析构函数的特性

  • 析构函数名是在类名前加上字符~
  • 无参数无返回值
  • 一个类有且只有一个析构函数。若未定义,则系统会自动生成默认的析构函数
  • 对象生命周期结束时,编译器系统会自动调用析构函数

3.4 析构函数按什么顺序析构

析构函数按照构造的相反顺序进行析构
 
原因:以为对象都在栈区,先构造的对象往栈底放,所以析构按构造的相反顺序进行析构

测试如下:

#include<iostream>
using namespace std;
class Test
{
   
public:
	Test(int data = 0)
	{
   
		m_data = data;
		cout << "Creat Test Obj:" <<this<< endl;
	}
	~Test()
	{
   
		cout << "Free Test Obj:" <<this<< endl;
	}
private:
	int m_data;
};
int main()
{
   
	Test t(12);
	{
   
		Test t1;
	}
	Test t2(3);
	return 0;
}


如上图所示,先构造了一个t对象,再构造了一个t1对象,t1对象的生命周期结束了,析构了t1对象,因为按照构造的相反方向析构,所以先析构t2对象,最后析构t对象

4. 拷贝构造函数(对象初始化对象的过程)

4.1 前言

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎,那么在创建对象时,是否可以创建一个与一个对象一模一样的新对象呢?

答案是可以的,我们可以使用拷贝构造函数来完成此操作

4.2 什么是拷贝构造函数

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

如下图所示就是一个拷贝构造函数:

4.3 拷贝构造函数的特性

  • 拷贝构造函数是构造函数的一个重载
  • 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值的方式会引发无穷递归调用
  • 若为定义,系统会生成默认的拷贝函数

4.4 拷贝构造函数参数中的const是否可以去掉

拷贝构造函数中的const不能去掉,const起到保护参数的作用,虽然去掉const后程序依然可以正常运行不会报错,但会出现传入的参数被修改的情况(const是语义要求)

验证如下:

4.5 拷贝构造函数参数中&是否可以去掉

拷贝构造函数参数中的&不能去掉,首先去掉&编译不能通过,若去掉,则是传值的方式会引发无穷递归调用;对象初始化对象会引发拷贝构造函数的调用,如下图所示:

5. 赋值重载函数

赋值重载函数:

  • 需要检测是否自己给自己赋值
  • 返回*this

如下图所示就是一个复制重载函数

6.普通对象的取址重载

用这种类型的指针接收这种类型对象的地址

如下图所示是一个普通对象的取址重载:

7.const对象的取址重载

注: 取地址及const取地址操作符这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况才需要重载,比如想让别人获取到指定内容


转载:https://blog.csdn.net/weixin_50886514/article/details/115572801
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场