c构造函数详解_构造函数有什么用

c构造函数详解_构造函数有什么用c++构造函数详解。(构造函数的分类、拷贝构造函数)

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

c++ 构造函数详解

构造函数是干什么的

  • 该类对象被创建的时候,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员

构造函数的分类

  • 无参构造函数
  • 带默认值的构造函数
  • 有参(无默认值)的构造函数
  • 复制构造函数(拷贝构造函数)
    • 一种特殊的构造函数,当对象之间复制时会自动调用拷贝构造函数
    • 若类中没有显示定义拷贝构造函数,则系统会自动生成默认拷贝构造函数
	#include <iostream>
	using namespace std;
	
	class Coordinate
	{ 
   
	public:
		// 无参构造函数
		// 如果创建一个类你没有写任何构造函数,则系统自动生成默认的构造函数,函数为空,什么都不干
		// 如果自己显示定义了一个构造函数,则不会调用系统的构造函数
		Coordinate()
		{ 
   
			c_x = 0;
			c_y = 0;
		}     
	
		// 一般构造函数
		Coordinate(double x, double y):c_x(x), c_y(y){ 
   }   //列表初始化
		// 一般构造函数可以有多个,创建对象时根据传入的参数不同调用不同的构造函数
	
		Coordinate(const Coordinate& c)
		{ 
   
			// 复制对象c中的数据成员
			c_x = c.c_x;
			c_y = c.c_y;
		}
	
		// 等号运算符重载
		Coordinate& operator= (const Coordinate& rhs)
		{ 
   
			// 首先检测等号右边的是否就是等号左边的对象本身,如果是,直接返回即可
			if(this == &rhs)
				return* this;
			// 复制等号右边的成员到左边的对象中
			this->c_x = rhs.c_x;
			this->c_y = rhs.c_y;
			return* this;
		}
	
		double get_x()
		{ 
   
			return c_x;
		}
	
		double get_y()
		{ 
   
			return c_y;
		}
	
	private:
		double c_x;
		double c_y;
	};
	
	int main()
	{ 
   
		// 调用无参构造函数,c1 = 0,c2 = 0
		Coordinate c1, c2;
		// 调用一般构造函数,调用显示定义构造函数
		Coordinate c3(1.0, 2.0);
		c1 = c3;    //将c3的值赋值给c1,调用"="重载
		Coordinate c5(c2);
		Coordinate c4 = c2;    // 调用浅拷贝函数,参数为c2
		cout<<"c1 = "<<"("<<c1.get_x()<<", "<<c1.get_y()<<")"<<endl
			<<"c2 = "<<"("<<c2.get_x()<<", "<<c2.get_y()<<")"<<endl
			<<"c3 = "<<"("<<c3.get_x()<<", "<<c3.get_y()<<")"<<endl
			<<"c4 = "<<"("<<c4.get_x()<<", "<<c4.get_y()<<")"<<endl
			<<"c5 = "<<"("<<c5.get_x()<<", "<<c5.get_y()<<")"<<endl;
		return 0;
	}
	c1 = (1, 2)
	c2 = (0, 0)
	c3 = (1, 2)
	c4 = (0, 0)
	c5 = (0, 0)
	请按任意键继续. . .

拷贝构造函数

  • 拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类型的引用。当定义一个新对象并用同一类型的对象都它进行初始化时,将显示使用拷贝构造函数,当该类型的对象传递给函数返回该类型的对象时,将隐式调用拷贝构造函数
  • 当类中有一个数据成员是指针时,或者有成员表示在构造函数中分配的其他资源,必须显示定义拷贝构造函数
  • 构造函数的使用情况
    • 一个对象以值传递的方式传入函数体
    • 一个对象以值传递的方式从函数体返回
    • 一个对象需要通过另一个对象进行初始化
	#include <iostream>
	using namespace std;
	
	class Test
	{ 
   
	public:
		// 构造函数
		Test(int a):t_a(a){ 
   
		cout<<"creat: "<<t_a<<endl;
		}
	
		// 拷贝构造函数
		Test(const Test& T)
		{ 
   
			t_a = T.t_a;
			cout<<"copy"<<endl;
		}
	
		// 析构函数
		~Test()
		{ 
   
			cout<<"delete: "<<t_a<<endl;
		}
	
		// 显示函数
		void show()
		{ 
   
			cout<<t_a<<endl; 
		}
	
	private:
		int t_a;
	};
	
	// 全局函数,传入的是对象
	void fun(Test C)
	{ 
   
		cout<<"test"<<endl;
	}
	
	int main()
	{ 
   
		Test t(1);
		// 函数中传入对象
		fun(t);
		return 0;
	}
	creat: 1
	copy
	test
	delete: 1
	delete: 1
	请按任意键继续. . .

浅拷贝与深拷贝

  • 浅拷贝
    • 所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。也就是增加了一个指针,指向原来已经存在的内存。 正常情况下,“浅拷贝”已经能很好的工作,但是一旦对象存在动态成员,浅拷贝就会出问题。让我们考虑下面一段代码:
	#include <iostream>
	#include <assert.h> 
	using namespace std;
	
	class Test
	{ 
   
	public:
		Test(){ 
   
			p = new int(10);
		}
	
		~Test(){ 
   
			assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行 
			delete p;
		}
	private:
		int x;
		int y;
		int* p;
	};
	
	int main()
	{ 
   
		Test t1;
		Test t2(t1);    // 调用默认拷贝构造函数
		return 0;
	}

上述程序崩溃。在使用t1复制t2时,进行的是浅拷贝,只是将成员的值进行赋值。此时,t1.p = t2.p, 即两个指针指向了堆里的同一个空间。这样,析构函数会被调用两次,这就是错误出现的原因。此问题的解决方法是“深拷贝”。

  • 深拷贝
    • 深拷贝就是对于对象中的动态成员,并不只是简单的赋值,而是重新分配空间,即资源重新分配。上述代码处理如下:
	#include <iostream>
	#include <assert.h> 
	using namespace std;
	
	class Test
	{ 
   
	public:
		Test(){ 
   
			x = 0;
			y = 0;
			p = new int(10);
		}
	
		Test(const Test& t)
		{ 
   
			x = t.x;
			y = t.y;
			p = new int(10);
			*p = *(t.p);
		}
	
		~Test(){ 
   
			assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行 
			delete p;
		}
	
		int get_x(){ 
   return x;}
		int get_y(){ 
   return y;}
	private:
		int x;
		int y;
		int* p;
	};
	
	int main()
	{ 
   
		Test t1;
		Test t2(t1);    // 调用默认拷贝构造函数
		cout<<"("<<t1.get_x()<<", "<<t1.get_y()<<")"<<endl
			<<"("<<t2.get_x()<<", "<<t2.get_y()<<")"<<endl;
		return 0;
	}
(0, 0)
(0, 0)
请按任意键继续. . .

此时t1与t2的p各自指向一段内存空间,但他们指向的内容相同,这就是“深拷贝”。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195919.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • freemarker错误九

    freemarker错误九

    2022年1月3日
    49
  • 【期末复习】微机原理与接口技术

    【期末复习】微机原理与接口技术知识重点整理第一章输入/输出系统1.接口电路的作用和基本功能接口电路是CPU与外设交换信息的中转站。接口电路应具备的功能为:数据缓冲功能、联络功能、寻址功能、数据转换功能、中断管理功能。2.端口的概念和分类端口是接口电路中能与CPU直接进行信息交换的寄存器,即I/O端口寄存器。在接口电路中,按端口寄存器存放信息的物理意义可划分为数据端口、控制端口和状态端口:数据端…

    2022年10月2日
    3
  • rc522 nfc_基于单片机的门禁系统

    rc522 nfc_基于单片机的门禁系统文章目录1.前言(包括一些个人理解)1.前言(包括一些个人理解)(2021/11/1编辑)在项目需要做一个NFC门禁功能的时候,突然发现有个RC522丢在我的桌面,甚至不知道它上面的引脚什么意思(还不会SPI通讯),搜索关键词“RC522”去看博客搜索资料,发现了很多都在说扇区,块,S50(M1)卡,然后就给代码,一开始我还以为S50是内嵌在这个模块里面的一个存储器,然后越看越怪,后面去淘宝搜索S50,才发现S50其实是我们的门禁卡,RC522是用来感应和判断的。…

    2025年12月5日
    6
  • anaconda和pycharm安装哪个版本好_pycharm专业版激活成功教程安装教程

    anaconda和pycharm安装哪个版本好_pycharm专业版激活成功教程安装教程文章目录Pycharm中嵌入AnacondaAnaconda下载Pycharm下载Anaconda安装Pycharm安装将Anaconda配置到Pycharm中添加一个python文件到工程Pycharm中嵌入AnacondaAnaconda下载关于这两个软件的介绍,相信不用我多说,大家都知道,Pycharm是一款很好用的Python的IDE支持很多牛逼的骚操作,而Anaconda则是一款集…

    2022年8月26日
    8
  • 金士顿有2t的u盘吗_群联3110主控

    金士顿有2t的u盘吗_群联3110主控最近新买的金士顿DT101G2U盘用老版本的群联检测工具GETinfo如GETinfov3.2.9.2会不认识MP的版本,一般会显示为MPv48.30.30,而使用新版本的如GETinfov3.5.7.2会显示MPALLv3.13.0B或MPALLv3.12.0A等。而这些版本网上都无释出版本的量产工具,怎么办呢,很多人都不知道该怎么选择量产工具的版本了。这里根据我成功…

    2025年10月14日
    5
  • 教你画出业务架构图「建议收藏」

    教你画出业务架构图「建议收藏」1、什么是业务架构图?业务架构图是一种表达业务层级和关系的工具,业务架构服务于业务目标,通过描绘业务上下层关系,梳理一整套完整、简单的业务视图,降低业务系统的复杂度,提高客户理解度,最终给客户最直观的业务体现。2、业务架构图的三大核心要义简单来说可以分为三个核心步骤:分层、分模块、分功能。架构图核心要义之一:分层指的是将业务按照层级区分,每个层级都属于独立的版块。下层更抽象,上层更具体。层级需要有逻辑上的关联,比如下层为上层服务,或者提供能力支撑。架构图核心要义之二:分模块分

    2022年10月12日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号