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++经典问题_01 C++构造函数和析构函数 -> 正文阅读

[C++知识库]C++经典问题_01 C++构造函数和析构函数

一. 构造函数的作用

  1. 当一个类对象在被创建的时候,编译系统对象分配内存空间,并且自动调用构造函数,由构造函数完成成员的初始化工作.所以构造函数的作用一般是用来初始化对象的数据成员.
  2. 如果代码里没有显示的定义构造函数,则编译器会自动创建默认的构造函数,以及默认的拷贝构造函数.
    默认的构造函数就是一个空实现,默认的拷贝构造函数是简单的属性赋值操作
  3. 如果显示的定义了构造函数,但是没有定义拷贝构造函数,编译器还是会创建一个默认的拷贝构造函数.作用就是将传递进来的对象的所有数据成员拷贝给正在创建的对象.

二.构造函数的分类

  1. 无参构造函数(如果用户没有提供任何的构造函数,则系统编译器会默认创建一个无参构造,就是一个空实现)
  2. 带默认值的构造函数
  3. 有参(无默认值)的构造函数
  4. 拷贝构造函数.(如果用户没有定义拷贝构造函数,则编译器会自动创建一个拷贝构造函数)
/*----------------------------------------------------------------
* 项目名称: Classical Question
* 作   者: Fioman
* 电   话: 13149920693
* 时   间: 2022/3/22
* 格   言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
	// 无参构造函数.
	// 如果没有定义任何的构造函数,则系统会创建一个默认的无参构造函数,函数体是空
	// 如果自己定义了构造函数,则不会调用系统的构造函数
	Person()
	{
		cout << "Person() 无参构造被调用!" << endl;

	}

	// 有参构造函数
	Person(string name, int age) :m_Name(name), m_Age(age) // 使用列表初始化进行赋值操作
	{
		cout << "Person()的有参构造函数被调用!" << endl;
	}

	// 拷贝构造函数
	Person(const Person &p)
	{
		m_Name = p.m_Name;
		m_Age = p.m_Age;
		cout << "Person()的拷贝构造函数被调用!" << endl;
	}

	~Person()
	{
		cout << "Person() 的析构函数被调用!" << endl;
	}

private:
	string m_Name;
	int m_Age = 0;
};

void test_person()
{
	// 调用无参构造
	Person p1;
	// 调用一般的有参构造函数
	Person p2 = Person("Fioman", 18);
	// 调用拷贝构造函数
	Person p3(p2);
}

int main()
{
	test_person();
	system("pause");
	return 0;
}

  • 运行结果:

三.拷贝构造函数

  • 拷贝构造函数是一种特殊的构造函数,一般有一个形参,常用const修饰是对该类型的引用.
  • 拷贝函数的调用时机
    1. 使用已经存在的对象创建初始化一个新对象.
    2. 值传递的方式给函数参数传值
    3. 值方式返回局部对象
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
	Person()
	{
		cout << "Person()的无参构造被调用!" << endl;
	}
	Person(string name,int age):mName(name),mAge(age)
	{
		cout << "Person的有参构造函数被调用!" << endl;
	}
	Person(const Person &p)
	{
		mName = p.mName;
		mAge = p.mAge;
		cout << "Person的拷贝构造函数被调用!" << endl;
	}
	~Person()
	{
		cout << "Person()的析构函数被调用!" << endl;
	}

	string getName(void)
	{
		return mName;
	}
	int getAge(void)
	{
		return mAge;
	}

private:
	string mName;
	int mAge = 0;
};

void test_copy_01(void)
{
	// 测试1,用已经创建的对象来初始化另外一个对象
	Person p1("Fioman", 18);
	Person p2(p1); // 调用拷贝构造函数
}
void doWork_01(Person p)
{

}

void test_copy_02(void)
{
	// 测试2,给另外一个函数传递参数
	doWork_01(Person("Fioman", 18));
	// 其中Person("Fioman",18)被称为是匿名变量,使用完即刻销毁
}

Person doWork_02(void)
{
	Person ret = Person("返回对象", 18);
	return ret; // 这里返回的实际上是Person对象ret的副本.会调用拷贝构造函数
}

void test_copy_03(void)
{
	// 测试3,作为局部对象进行返回的时候,实际上返回的是一个副本,所以会调用拷贝构造函数
	Person p;
	p = doWork_02();
}

int main()
{
	test_copy_01();

	system("pause");
	return 0;
}

四. 浅拷贝和深拷贝

何为浅拷贝

将原对象中每一个成员字段的值都拷贝到新对象中.这对于普通变量来说没有问题,但是对于指针类型的变量就有问题.因为指针所指向的内存都是动态分配的,并不会自动得到拷贝.这导致原对象和新对象中的字段,全部指向同一块动态分配的内存.

哪些情况下会执行浅拷贝

  1. 系统创建的默认拷贝构造函数
  2. 系统默认的赋值运算符

浅拷贝引发的问题

  1. 如果对象的成员没有指针变量,浅拷贝是没有问题的.但是一旦有了指针变量.指针变量实际上存储的是另一个变量的地址,浅拷贝只是将这个地址拷贝给新对象,并没有给该地址上存储的变量开辟空间并拷贝,所以如果出现原对象已经将该地址释放了,新对象在析构的时候,会再释放一次,造成重复释放同一块内存.
  2. 两个指针指向同一个内存空间,任意一个指针对该内存进行操作,都会影响另外一个指针.

#include <iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person()
	{
		cout << "默认的无参构造函数被调用!" << endl;
	}
	Person(string name,int age)
	{
		mAge = new int(age);
		cout << "Person()的有参构造被调用!" << endl;

	}

	Person(const Person &p)
	{
		mName = p.mName;
		mAge = p.mAge;
		cout << "拷贝构造函数被调用!" << endl;
	}
	~Person()
	{
		if (mAge != nullptr)
		{
			delete mAge; 
			mAge = nullptr;
		}
		cout << "析构函数被调用,释放指针!" << endl;
	}

private:
	string mName;
	int *mAge = nullptr;
};

void test_shallow_copy(void)
{
	// 测试浅拷贝的问题.
	Person p1("Fioman", 12);
	Person p2(p1);
}

int main()
{

	test_shallow_copy();
	system("pause");
	return 0;
}

解析:

代码运行的过程中会报错,因为指针变量mAge,被释放了两次.

何为深拷贝

深拷贝是指不仅拷贝原对象中的每一个字段,而且将动态分配给该字段的内存内容一并拷贝过来.
所有在面对有指针属性的变量的时候,我们必须编写拷贝函数,并重载运算符.深拷贝会在堆中另外申请空间来存储数据,从而解决指针悬挂的问题.

  • 把上面的例子改成深拷贝就不会有这种问题了.
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
#include<string>
using namespace std;

class Person
{
public:
	Person()
	{
		cout << "默认的无参构造函数被调用!" << endl;
	}
	Person(string name, int age)
	{
		mAge = new int(age);
		cout << "Person()的有参构造被调用!" << endl;

	}

	Person(const Person &p)
	{
		mName = p.mName;
		//mAge = p.mAge; 直接拷贝,浅拷贝,当面对指针变量的时候有问题
		mAge = new int(*p.mAge);
		cout << "拷贝构造函数被调用!" << endl;
	}
	~Person()
	{
		if (mAge != nullptr)
		{
			delete mAge;
			mAge = nullptr;
		}
		cout << "析构函数被调用,释放指针!" << endl;
	}

private:
	string mName;
	int *mAge = nullptr;
};

void test_shallow_copy(void)
{
	// 测试浅拷贝的问题.
	Person p1("Fioman", 12);
	Person p2(p1);
}

int main()
{

	test_shallow_copy();
	system("pause");
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:18:35  更:2022-03-24 00:18:46 
 
开发: 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 1:32:40-

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