C++中构造函数的超详细讲解

2023-05-16

C++在C语言的基础上增加了类和对象的概念,官方对类和对象的解释是:对象是类的实例化,类是对象的抽象,其实这个概念也很抽象,举一个简单的例子来说明这个关系:

在汽车生产车间我们要先画一张完整的汽车设计图后再通过组装零件来完成汽车的制造,而这里的图纸就相当于C++中的类,通过图纸生产的汽车就是对象,所以汽车就是对图纸的实例化,图纸就是汽车的抽象化,而构造函数就充当了一个很重要的角色。

重点:以上述例子为例:什么被称为汽车呢,那应该是具有了汽车的特征,如四个轮子,一个 发动机,一个方向盘等等,所以我们之所以称它为一辆汽车,是因为它有了汽车的所有特征,如果少了轮子或者方向盘那么都不叫一个完整的汽车,对象亦是如此,我们定义了一个类去实例化一个对象时那么这个对象就应该有该类所应有的特征,所以构造函数的功能就是帮我们在实例化一个对象时能够自动的完成这个对象的初始化,例如我们在定义一个Triangle 类,那么一个三角形的特征是什么呢,或者说我们需要什么才能够描述出一个三角形呢,那就是三角形的三条边 a,b,c,所以我们定义的Triangle 这个类中就应该有三角形的三条边a,b,c,假如没有使用构造函数,那么我们实例化好一个对象后,该对象的成员数据a,b,c 都会是一个不确定的值,既然是不确定的值那么它就很有可能不是一个三角形,因为三角形的成立条件是a+b>c ,所以就不能称之为三角形,那么这个对象的实例化就失败了。所以构造函数就能解决这个问题。

通过上诉例子,我们就来介绍构造函数,构造函数主要有两种(一共三种),普通构造,拷贝构造分别能够为不同种类的成员赋值(由于另一种移动构造设计运算符重载,所以会有一篇关于它的文章),其中构造函数有以下几个重要的特征:

1,构造函数名与类名相同,且无返回值(void也不行)

2,在每一个类中都有存在有默认的构造函数(系统自行提供),且在实例化对象时都会调用,        只是默认不做任何事情

3,构造函数会在实例化对象时自动调用,不允许显式调用

下面我们逐一进行详细介绍。

一,普通构造函数

普通构造函数中分为有参构造函数和无参构造函数,即带参数的构造函数和不带参数的构造函数,上面说到系统默认提供的构造函数就是无参构造,默认不做任何事,如果我们自己写了构造函数,系统便不再使用默认构造函数,而是调用我们自己写的构造函数,这就叫构造函数的重写,我们通过一个小小的例子来证明构造函数是系统自动调用的

#include<iostream>
using namespace std;
class Triangle          //三角形类
{
	public:
		Triangle()                 //重写构造函数
		{
			cout<<"无参构造"<<endl;
		}
		private:
			int a;
			int b;
			int c;
};
int main()
{
	Triangle A;                //实例化对象
}

执行结果如下:

 结论1:上述例子中我们并没有手动调用构造函数,仅仅只做了实例化对象这一个操作,但是构造函数还是被执行了,这就证明了构造函数是在实例化对象时系统自动调用的。

诶,通过上面的例子是不是就可以想到怎么利用构造函数来进行简单的成员变量初始化了,没错,我们在上述函数的基础上稍加修改就可以实现。

#include<iostream>
using namespace std;
class Triangle
{
	public:
		Triangle()
		{
			cout<<"无参构造"<<endl;
			a=3;
			b=4;
			c=5;
		}
		void getValue()                 //成员函数(打印成员变量值)
		{
			cout<<"a="<<a<<endl;
			cout<<"b="<<b<<endl;
			cout<<"c="<<c<<endl;
		}
		private:
			int a;
			int b;
			int c;
};
int main()
{
	Triangle A;
	A.getValue();                  //调用成员函数
}

 

 通过这种方法就可以实现最简单的成员变量初始化,但是基本不这样用,因为除了可以初始化之外没有任何意义,所以我们就来说普通构造的第二种,有参构造。

以上述例子为例,那么有参构造的形式如下:

Triangle(int a,int b,int c)                    //参数名随意
		{
			cout<<"有参构造"<<endl;
			this->a=a;                    //为每个成员赋值
			this->b=b;
			this->c=c;
		}

 通过传进来的参数来为成员变量赋值,那么程序的灵活性就会更高,调用方式也很简单,只需在实例化对象时给对象传入参数即可

Triangle A(3,4,5);                  //分别为对应参数传参

 结果如下:

 这样我们就能够根据需求在实例化对象时传入不同的参数来赋值,很简单吧。接下来介绍第二种

 二,拷贝构造函数

 在实际需求中我们不仅仅需要为对象赋予基本的数值,比如我现在又实例化了另一个对象,我想把这个对象中的所有成员或特定的成员赋值给另一个时,这时候使用普通构造函数就不能实现这个功能了,于是就有了拷贝构造函数,拷贝构造函数就是专门用于同一类对象的赋值,其实系统也有默认的拷贝构造函数,我们也来证明以下看看它是否真正存在。

#include<iostream>
using namespace std;
class Triangle
{
	public:
		Triangle()                   //无参构造
		{
			cout<<"无参构造"<<endl;
		}

		private:
			int a;
			int b;
			int c;
};
int main()
{
	Triangle A;                //使用无参构造初始化A
	Triangle B(A);               //使用拷贝构造初始化B
}

 有小伙伴是不是发现了什么,在上面我们明明实例化了两个对象啊,怎么只调用了一次无参构造呢,另外一个呢。其实我们的对象B调用了系统默认的拷贝构造,因为在现实需求中,这种初始化的方式很常见,所以系统就干脆弄了一个默认的拷贝构造供用户使用,同样,如果我们对拷贝构造函数进行重写,那么默认的就不再发挥作用而是使用我们自己写的,拷贝构造定义和调用如下:

 

#include<iostream>
using namespace std;
class Triangle
{
	public:
		Triangle(int a,int b,int c)          //有参构造           
		{
			this->a=a;
			this->b=b;
			this->c=c;
			cout<<"有参构造"<<endl;
		}
		Triangle(Triangle &obj)                 //拷贝构造
		{
			a=obj.a;                 //通过目标对象对每个成员变量赋值
			b=obj.b;
			c=obj.c;
			cout<<"拷贝构造"<<endl;
		} 
		void getValue()                   //成员函数
		{
			cout<<"a="<<a<<endl;
			cout<<"b="<<b<<endl;
			cout<<"c="<<c<<endl;
		}

		private:
			int a;
			int b;
			int c;
};
int main()
{
	Triangle A(3,4,5);                    //A调用了有参构造
	Triangle B(A);                        //B调用了拷贝构造
	B.getValue();
}

 这样就可以直接通过对象给对象赋值实现初始化了,很方便。但是人们后面又发现了这种拷贝构造存在一个缺陷,那就是如果对象中存在指针的时候就会发现一个问题,在对指针指向内存进行释放时会造成重复释放,这显然就有问题了,那么我们如何证明呢,这时就浅说以下析构函数,大家现在只需知道析构函数是用来干嘛的,析构函数是用于对象生命周期结束时自动释放对象所占资源的函数,它也是系统自动调用的,当然我们进行重写来展现效果ok,已经够我们证明之前的结论了。

假如我们已经定义了一个Mystring类,类中有指针成员p,现在我们实例化了两个对象str1,str2,为对象str2指针初始化为" hello ",假设字符串" hello "的地址为0x0001,现在我们通过拷贝构造使用str2来初始化str1,会进行如下操作: 

 这时我们就会发现str1的p和str2的p指向的不都是同一片地址吗,怎么释放了两次,这显然不得行,所以我们就把这种系统默认的拷贝构造函数称为浅拷贝,也就是我们之前说的拷贝构造都是浅拷贝,它只会对值进行赋值而不管值类型的特殊带来的后果,所以我们在对含有指针成员的对象进行拷贝构造初始化时就需要使用深拷贝(必须重写,不然就会默认使用系统的浅拷贝),深拷贝的原理如下:

 这样str1的p就不再和str2中的p指向同一片空间了,所以在对象被析构函数释放后也不会对新开辟的空间进行重复释放,就解决了浅拷贝中重复释放空间的问题,深拷贝具体代码如下:

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

class Mystring
{
	public:
		~Mystring()
		{
			delete p;
			cout<<"析构函数"<<endl;
		}
		Mystring(char* str)                   //有参构造 
		{
			p=new char[strlen(str)+1];
			strcpy(p,str);
		}
		Mystring(Mystring &obj)                     //深拷贝 
		{
			p=new char[strlen(obj.p)];             //申请新的空间 
			strcpy(p,obj.p);                    //将目标对象的内容复制到自身空间 
		}
		void print()
		{
			cout<<p<<endl;
		}
		private:
			char* p;
};
int main()
{ 
	Mystring str1("hello");                    //使用有参构造初始化str1
	Mystring str2(str1);                       //使用深拷贝用str1初始化str2
	str2.print();
}

 

 其实深拷贝和浅拷贝的区别就是有没有赋值之前为新对象的指针成员开辟空间

总结:1,系统提供了一种构造函数可以实现同类对象之间进行直接赋值初始化,这种叫浅拷贝

           2,如果需要赋值的对象成员有指针,那么就必须重写拷贝构造进行深拷贝,注意是必须,不然会造成内存泄露。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中构造函数的超详细讲解 的相关文章

  • android 焦点事件

    今天介绍下android中的焦点事件 xff0c 之前在项目有用到过 这块不是很难 xff0c 大家跟着过一遍吧 xff0c 用到的时候直接把我下面这段代码拷贝过去就ok了 1 建一个工程 xff0c 名为TestFocus 2 在布局文件
  • android 绘图、自定义组件

    我们在开发当中很多时候都需要自定义组件 xff0c 通过自定义组件 xff0c 可以随心所欲定制酷炫的效果 下面将演示自定义绘图组件 我们要绘制一个红色的线条 1 建立工程文件 xff0c 名为TouchDemo 2 布局文件 lt xml
  • SVN常用命令详解

    命令的使用 1 检出 svn co http 路径 目录或文件的全路径 本地目录全路径 username 用户名 password 密码svn co svn 路径 目录或文件的全路径 本地目录全路径 username用户名 password
  • androidstudio 拆包时设置dex方法个数

    前言 Android应用程序 xff0c 最终发布成一个apk xff0c 安装到手机上 apk文件随便用一个解压缩文件打开 xff0c 可以看到里面有一个classes dex文件 xff0c 这就是之前工程中所有的代码 xff0c 以及
  • hash算法原理详解

    散列表 它是基于快速存取的角度设计的 xff0c 也是一种典型的 空间换时间 的做法 顾名思义 xff0c 该数据结构可以理解为一个线性表 xff0c 但是其中的元素不是紧密排列的 xff0c 而是可能存在空隙 散列表 xff08 Hash
  • Android Studio 打包时 Signature Version 选择 V1 V2 说明

    问题描述 v1和v2 Android 7 0中引入了APK Signature Scheme v2 xff0c v1是jar Signature来自JDK V1 xff1a 应该是通过ZIP条目进行验证 xff0c 这样APK 签署后可进行
  • Android 多Dex分包机制

    问题引入 随着项目工程越来越庞大 xff0c 代码的方法数不断增长到一定程度 xff0c 就出现Android 低版本系统应用无法安装的情况 那么这是哪里出错了 xff1f Android系统对安装包有哪些限制 xff1f 前一阵子 xff
  • 安装openstack时碰到的错误

    文章目录 目录安装keystone identity时遇到的错误信息glance验证操作错误信息计算节点安装openstack nova compute找不到包openstack nova compute安装后服务起不来openstack
  • Linux什么时候能代替Windows?现在有什么困难?2022新一年Linux目标

    我举出一个身边例子 xff1a 昨天 xff0c 我的一个亲戚的电脑坏了 xff0c 是一个七八年前配置笔记本电脑 xff0c 找我修 xff0c 我本来想安装Windows10 xff0c 但是想到现在我电脑的主系统都是Linux了 xf
  • apt-get update error解决方法

    apt get update error Unable to lock the administration directory var lib dpkg is another proc root 64 ony an opt devstac
  • PVE安装win10并开启远程桌面

    接上一篇 一 win10安装镜像最新版下载 下载地址 xff1a https next itellyou cn 现在的win10最新版时22h2 文件名为zh cn windows 10 business editions version
  • Win10相机打开后显示灰色的原因(仅适用于联想笔记本)

    症状描述 xff1a 打开相机 xff0c 显示灰色 xff0c 中间有一个相机带斜杠的图标 我先说解决方法 xff0c 再吐槽 xff1a 如果网上的方法都不行 xff0c 就检查自己的笔记本是否安装了联想电脑管家 xff0c 如果有 x
  • Visual Studio 2015 tools for Unity 安装使用

    P1 xff1a 安装 微软好像把这个工具整合在Visual studio 2015一起了 xff0c 没找到单独的链接 CSDN链接 xff1a http download csdn net detail devilsomezeng 95
  • VMware部署Debian系统

    前面在手机和平板上安装了UserLAnd软件 xff0c 初步实现了随身携带Linux系统的小目标 但是前面也提到了目前存在一个小问题 xff0c 那就是没有办法远程登录 xff0c 简单调整了一下还没解决 xff0c 看来还是要简单学习一
  • Openstack关于Regions和Availability Zones

    声明 xff1a 本博客欢迎转发 xff0c 但请保留原作者信息 内容系本人学习 研究和总结 xff0c 如有雷同 xff0c 实属荣幸 xff01 原文地址 xff1a http blog csdn net gtt116 在AWS中有Re
  • Manjaro 安装搜狗输入法

    经历了长时间搜索和实践 xff0c 我终于安装好了搜狗输入法 xff0c 基本套路就还是按照大多数博客介绍的命令行装的 xff1a sudo pacman S fcitx im sudo pacman S fcitx configtool
  • layui:弹窗跨域问题 Uncaught DOMException: Blocked a frame with origin

    在日常开发中经常出现A系统调用B系统的相关功能 xff0c 在B系统中进行layer弹窗时 xff0c 提示错误信息 Uncaught DOMException xff0c 经过查询网上资料 xff0c 发现是跨域错误 仔细检查代码 xff
  • CentOS安装最新稳定版Jenkins

    文章目录 1 Java版本兼容列表2 JDK安装3 Jenkins安装3 1 定义Jenkins RPM仓库3 2 进行安装 4 Jenkins启动4 1 指定Java程序4 2 相关命令 5 FAQ5 1 目录介绍5 2 AWT is n
  • Codeforces Global Round 21参考代码

    Codeforces Global Round 21 A xff1a include lt iostream gt include lt algorithm gt include lt cstdio gt include lt cstrin

随机推荐

  • 有设计才艺的小伙伴千万不要错过GIMP

    GIMP是一个非常好的位图设计软件 xff01 支持LInux系统 xff0c Windows系统 xff0c Mac xff0c GIMP一直陪着我从Windows转到Linux xff0c 直到现在还在用 个人感觉比PhotoShop强
  • python下载

    python下载 1 打开python官网 网址 xff1a python org 1 1按照对应的操作系统选择 1 2下滑找到3 10 0 版本根据电脑配置选择64位或者32位 一般选择左列的稳定发行版 注意 xff0c 这里有embed
  • Android 捕获主线程异常崩溃

    一般情况下我们想要捕获全局异常会调用Thread setDefaultUncaughtExceptionHandler方法 xff1b 这个方法虽然能捕获所有线程的异常 xff0c 但如果是主线程发生未捕获异常 xff0c APP虽然不会崩
  • 使用cmake编译一段代码时出现VS2015 The C/CXX compiler identification is unknown

    打开CmakeError log 里面有如下错误 xff1a D Program Files Microsoft Visual Studio 14 0 VC bin x86 amd64 link exe ERRORREPORT QUEUE
  • Ubuntu安装VirtualBox6.1,报错依赖于libqt5opengl5...

    自己在安装Vbox6 1时遇到依赖问题 xff0c 多次尝试无法解决 xff0c 最后找到以下解决方法 由于网上看到的很多方法并不能解决问题 xff0c 这里将原文做转载 xff0c 希望能帮助到更多的人 1 方法一 xff1a 从Ubun
  • Debian 10(buster) 更换可用的国内软件源

    由于Debian 10 xff08 buster xff09 还比较新 xff0c 有很多源都使用不了 xff0c 有的还连接不上 xff0c 以下是亲自试过可以使用的源 xff0c 需要的小伙伴可以试试 163源 deb cdrom De
  • ubuntu 下搭建 Jenkins 并配置部署环境

    转载 xff1a https www cnblogs com shuoer p 9471839 html 前言 xff1a 因为要搭建Jenkins xff0c 试了很多办法都不行 xff0c 后来找到这篇博客装好了 xff0c 分享下 x
  • 批处理文件(.dat/.cmd)打开多个文件

    在window下 xff0c 有时候经常需要一次性打开多个文件 xff0c 如果都在一个目录下还好 xff0c 但是如果需要打开的文件分布在各个地方 xff0c 逐一打开还是挺麻烦的 通过批处理可以偷下懒 废话少说 xff0c 例文如下 x
  • STC 定时器/计数器2 操作详解 (基于STC89C52RC参考文档)

    一 认识STC定时器2 T2 STC 定时器2 xff08 即T2 xff09 是一个16位定时 计数器 通过设置特殊功能寄存器T2CON中的C T2位 xff0c 可将其作为定时器或计数器 xff08 特殊功能寄存器T2CON的描述如表1
  • 第五周作业 C题

    C题 平衡字符串 题目描述 xff1a 一个长度为 n 的字符串 s xff0c 其中仅包含 Q W E R 四种字符 如果四种字符在字符串中出现次数均为 n 4 xff0c 则其为一个平衡字符串 现可以将 s 中连续的一段子串替换成相同长
  • 第八周作业 B题

    B 猫猫向前冲 题目描述 xff1a 众所周知 xff0c TT 是一位重度爱猫人士 xff0c 他有一只神奇的魔法猫 有一天 xff0c TT 在 B 站上观看猫猫的比赛 一共有 N 只猫猫 xff0c 编号依次为1 xff0c 2 xf
  • Linux安装Git和GitLab,最新教程,细到极致

    大家早上好呀 xff0c 又到了周末了 xff0c 心情很舒服 摸鱼了一上午 xff0c 想要写点东西 今天给大家带来的是 xff0c git和GitLab的安装 快速定位到Gitlab安装 话不多说 xff0c 开始吧 1 创建git文件
  • Ubuntu安装搜狗输入法无论如何就是找不到的解决方法///Ubuntu怎么安装搜狗输入法///Ubuntu怎么输入中文///Ubuntu搜狗输入法怎么修改皮肤

    我刚装上ibus的时候 xff0c 感觉一点也不好用 xff0c 于是就换成了fcitx打算安装搜狗输入法for Linux xff0c 结果各种方法都试过了 xff0c 无论如何都找不到搜狗输入法 xff0c 我偶然把fcitx5换成了f
  • iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图

    话不多说 xff0c 先来看看效果 xff1a 1 饼图 扇形图 2 柱状图 3 折线图 样子粗糙 xff0c 见笑了 现在来看看实现过程 一 饼图 扇形图 1 实现思路 实现思路其实很简单 xff0c 首先算传入数据数组的数据总和 xff
  • debian小巧好看的桌面

    先看完 xff0c 不然 xff0c 你一定会后悔的 不好看 xff0c 你打我 sudo apt get install xfce4 sudo apt get install xfce4 goodies sudo apt get inst
  • ubuntu下安装arm-linux-gcc交叉编译链

    你好 xff01 这里是风筝的博客 xff0c 欢迎和我一起交流 交叉编译链下载地址 xff1a ftp ftp gnu org gnu gcc 或者在arm官网下载 https developer arm com open source
  • 嵌入式Linux驱动笔记(二十一)------GPIO和Pinctrl子系统的分析和思考

    你好 xff01 这里是风筝的博客 xff0c 欢迎和我一起交流 好久都没有写东西了 xff0c 最近来广州某公司实习 xff0c 顺便记录下吧 吐槽下 xff0c 因为是二级保密单位 xff0c 公司里电脑不给联网 xff0c 贼难受 不
  • Feign和RestTemplate 的使用比较

    Feign和RestTemplate 的使用比较 一 RestTemplate 基于RestTemplate 进行远程服务调用 但是在调用之前基于loadBalancerClient对象去从nacos注册中心基于服务名查找服务实例 可能有多
  • ubuntu16.04 配置远程桌面

    sudo apt get y install xfce4 xrdp vnc4serverdpkg L xrdp 在显示的结果中有如下一行即可 xff1a etc xrdp xrdp ini配置xfce4桌面会话文件 软件安装完毕后 xff0
  • C++中构造函数的超详细讲解

    C 43 43 在C语言的基础上增加了类和对象的概念 xff0c 官方对类和对象的解释是 xff1a 对象是类的实例化 xff0c 类是对象的抽象 xff0c 其实这个概念也很抽象 xff0c 举一个简单的例子来说明这个关系 xff1a 在