IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++之构造函数 -> 正文阅读

[C++知识库]C++之构造函数

1.什么是构造函数?
创建一个对象之后,就需要初始化该对象,构造函数就是用来初始化该对象的。
2.构造函数有什么作用?
构造函数的作用是初始化对象的数据成员。类对象被创建的时候,编译系统为对象分配内存空间,并自动调用该构造函数,由构造函数完成初始化工作。
3.构造函数的分类有哪些?

  • 无参构造函数
  • 待默认值的构造函数
  • 有参构造函数
  • 拷贝构造函数
    • 一种特殊的构造函数,当对象之间复制时会自动调用拷贝构造函数
    • 若类中没有定义拷贝构造函数,系统会自动生成一个拷贝构造函数
    • 拷贝构造函数具有单个形参,该形参(常用const修饰)是对该类型的引用,当定义一个新对象并对他进行初始化时,将显示调用拷贝构造函数,当该类型的对象传递给函数返回该类型的对象时,将隐式调用拷贝构造函数
    • 当类中有一个数据成员是指针时,或者有成员表示在构造函数中分配的其它资源,必须显示调用拷贝构造函数。

4.浅拷贝和深拷贝的区别?
对于下边的拷贝构造函数,如果在拷贝name时,直接写为:

_name=src._name

那么在析构时,新对象和旧对象就会析构同一块内存空间,程序就会奔溃;
而深拷贝就是重新为新对象开辟一段内存空间,不只是简单地赋值
。(就好比你的作业写完了,你的同桌拿去看了,但是你的同桌不能交你的作业,因为你还要交,而一份作业不能交两次,所以你的同桌要交作业的话,就必须照着你的作业抄一份,然后你们各交各的)

下边我们通过一个代码来详细了解构造函数:

#include<iostream>
using namespace std;
class Person
{
public:
	int _age;
	int _sex;
	char* _name;//成员属性
	Person()//默认构造函数
	{
		_name = NULL;
		cout << "Person()" << endl;
	}

	Person(int age)//带一个参数的构造函数
	{
		cout << "Person(int age)" << endl;
		_age = age;
		_name = NULL;
	}
	Person(int age, int sex,const char* name)//带多个参数的构造函数
	{
		cout << "Person(int age, int sex,  char* name)" << endl;
		_age = age;
		_sex = sex;
		//_name = name;//浅拷贝 指针给指针赋值
		//深拷贝
		_name = new char[strlen(name) + 1];
		memset(_name, 0, strlen(name) + 1);
		for (int i = 0; i < strlen(name); i++)
		{
			_name[i] = name[i];
		}
	}
	Person(const Person& src)//拷贝构造函数
	{
		cout << "Person( Person src)" << endl;
		_age = src._age;
		_sex = src._sex;
		//预防浅拷贝
		if (NULL != src._name)
		{
			_name = new char[strlen(src._name) + 1];
			memset(_name, 0, strlen(src._name) + 1);
			for (int i = 0; i < strlen(src._name); i++)
			{
				_name[i] = src._name[i];
			}
		}
		else
		{
			_name = NULL;
		}
	}
	Person& operator=(const Person& src)//等号运算符重载
	{
		cout << "void operator=(const Person& src)" << endl;
		//防止自赋值 
		if (this == &src)
		{
			return *this;
		}
		//防止内存泄漏
		delete[]_name;
		//防止浅拷贝
		if (NULL != src._name)
		{
			_name = new char[strlen(src._name) + 1];
			memset(_name, 0, strlen(src._name) + 1);
			for (int i = 0; i < strlen(src._name); i++)
			{
				_name[i] = src._name[i];
			}
		}
		else
		{
			_name = NULL;
		}
	}

	
	~Person()//析构函数
	{
		if (NULL != _name)
		{
			cout << _name << endl;
		}
		cout << "~Person()" << endl;
		if (NULL != _name)
		{
			delete[]_name;
		}
		_name = NULL;
	}
	void work(/* Person *this */)//每一个成员方法在传参的时候都会默认传一个this指针
	{
		//this = NULL;
		cout <<_name<<":work" << endl;//默认加上this的解引用 this->_name
		eat();//this->_eat;
	}
	void eat()//普通成员函数
	{
		cout << _name<<"eat" << endl;
	}
	void show()
	{
		if (NULL != _name)
		{
			cout << "name:" << _name << endl;
		}
		cout << "age:" << _age << endl;
		cout << "sex" << _sex << endl;
	}
};
//
Person fun(Person& p)
{
	int a = 10;
	Person tmp(10);
	return tmp;//返回一个对象 不可以返回引用,函数调用结束之后,底层指针就会变为野指针
}
int main()
{
    //测试模块一:
	Person p1;
	//p1._name = "zhangsan";//c++中不可以把常量字符串赋值给非常量指针,这句会报错
	char name[] = { "zhangsan" };
	p1._name = name;
	p1.eat();//默认取哪个对象,就取哪个对象的地址
	
	//测试模块二:
	char name[] = { "zhangsan" };
	Person p1(32, 1, name);
	p1.show();

	Person p2;
	Person p3();//对象名之后不可加(),否则系统按照函数声明处理掉了

    //测试模块三:
    char name[] = { "zhangsan" };
	Person p1(32, 1, name);
	Person p2(p1);//拷贝构造
	p1.show();
	p2.show();
	
    //测试模块四
	Person p3(15,1,"lisi");
	p3 = p2 = p1;
	p3.show();
     
    //测试模块五:
	Person p1(31, 1, "zhangsan");//三个函数都能构造
    Person* p2 = new Person();//没有参数构造
    delete p2; 
    
    //测试模块六
	Person p3;//没有参数构造
	Person p4 = 20;//一个参数构造
	//使用20生成临时对象
	//使用临时对象拷贝p4
	//析构临时对象
	//如果出现上述步骤顺序,会被直接优化成构造p4
	Person p5 = p3;//拷贝构造
	Person p6(p3);//拷贝构造
    
    //测试模块七
    Person p3;
	p3 = fun(p3);
	Person p4 = fun(p3);
	return 0;
}

测试模块一:调用无参构造函数
在这里插入图片描述
测试模块二:调用有参构造函数,先构造后析构
在这里插入图片描述
测试模块三:先调用普通构造对成员变量进行初始化,再调用拷贝构造函数构造一个新对象p2,同时对p2的成员变量进行初始化。
在这里插入图片描述
测试模块四:赋值运算符的“=”是属于后边对象的,因为p2的name为空,所以p3的name也被置空
在这里插入图片描述
如果为“p2=p3",则执行结果就会出现name
在这里插入图片描述
测试模块五:
在这里插入图片描述
测试模块六:拷贝构造函数是用一个已经存在的对象去构造一个新的对象,而等号赋值运算符的两个对象都是已经存在的
在这里插入图片描述
特别注意:这里有一个优化构造概念
在这里插入图片描述
测试模块七:

  • 先构造p3;
  • 再构造临时临时对象tmp;
  • 用tmp拷贝构造一个返回值对象;(return tmp)
  • 函数执行完成,析构临时变量tmp;
  • 因为p3已经存在,所以“p3 = fun(p3)"调用赋值运算符重载函数,用返回值对象给p3赋值;
  • 析构返回值对象;
  • 再构造临时对象tmp;
  • 再构造返回值对象;
  • 再用返回值对象构造p4;(以上三步符合优化构造的条件,所以这里直接为构造p4) ;
  • 析构临时对象;
  • 析构返回值对象;(相当于析构p4) 析构p3

在这里插入图片描述
构造函数部分参考:https://blog.csdn.net/qq_29339467/article/details/90719951.

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 21:25:37  更:2021-11-14 21:26:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:35:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码