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;                //使用无参构造初始化ATriangle 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");                    //使用有参构造初始化str1Mystring str2(str1);                       //使用深拷贝用str1初始化str2str2.print();
}

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

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

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

C++中构造函数的超详细讲解相关推荐

  1. 生存曲线 p值 python_超详细讲解生信SCI中的生存曲线作图,不看后悔系列

    原标题:超详细讲解生信SCI中的生存曲线作图,不看后悔系列 在线及个性化精美Kaplan-Meier生存曲线的绘制 大家好,我是阿琛.俗话说,是骡子是马拉出来溜溜.在肿瘤研究中,一个基因的研究价值高不 ...

  2. python中逻辑运算符and,or的用法以及运算的核心思想——“短路逻辑”超详细讲解

    python中and和or的用法以及运算的核心思想--"短路逻辑"超详细讲解 //本文几乎涵盖了and和or所有知识点,篇幅较长,一点要静下心来看,学无止境. 1.and和or的含 ...

  3. react的超详细讲解

    create-react-app 项目目录 在HTML中使用react 1 2 3基础 React的注意事项 模拟的React 和 render React组件 函数组件 类组件 React 的数据源 ...

  4. Python的零基础超详细讲解(第十三天)-Python的类与对象

    基础篇往期文章如下: Python的零基础超详细讲解(第一天)-Python简介以及下载 Python的零基础超详细讲解(第二天)-Python的基础语法1 Python的零基础超详细讲解(第三天)- ...

  5. Python的零基础超详细讲解(第十二天)-Python函数及使用

    基础篇往期文章: Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博 ...

  6. Python的零基础超详细讲解(第七天)-Python的数据的应用

    往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...

  7. Python的零基础超详细讲解(第五天)-Python的运算符

    往期文章 Python的零基础超详细讲解(第一天)-Python简介以及下载_编程简单学的博客-CSDN博客 Python的零基础超详细讲解(第二天)-Python的基础语法1_编程简单学的博客-CS ...

  8. python高级语法装饰器_Python高级编程——装饰器Decorator超详细讲解上

    Python高级编程--装饰器Decorator超详细讲解(上篇) 送你小心心记得关注我哦!! 进入正文 全文摘要 装饰器decorator,是python语言的重要特性,我们平时都会遇到,无论是面向 ...

  9. mybatis-plus超详细讲解

    (6条消息) mybatis-plus超详细讲解_zdsg45的博客-CSDN博客_mybatis-plushttps://blog.csdn.net/zdsg45/article/details/1 ...

最新文章

  1. mysql5.5.42指定数据库同步操作
  2. 随机生成50个字段的elasticsearch的测试程序输入
  3. 编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码
  4. android 生成纯色,android – 以编程方式添加具有纯色和笔触的渐变
  5. JDK 8与JDK 10:三元/拆箱的区别
  6. 验证码一(验证码生成)
  7. sqlserver操作符篇 优化
  8. 用termux打开python文件,安卓手机运行python程序的软件:Termux、Pydroid3
  9. QA智能问答(QQ匹配)
  10. 碎片时间都在刷手机?RSSHub带你逃出信息洪流!
  11. STM32F4之ADC介绍
  12. 【理财入门一】三大资产与财务自由
  13. 常用的数据库统计SQL语句(2)
  14. Android底层和中间层共同学习系列之android键盘映射
  15. 周测三,Linux命令如下:
  16. PUCCH(2)格式与DTX检测(源于5G上行控制信道增强技术研究)
  17. AXI_Round_Robin_Arbiter 设计 - AW、W通道部分
  18. outlook2007突然打不开的解决方案
  19. AE 动效工作流技巧 —— 减少 Bodymovin 导出的 JSON 大小并提升性能(一)
  20. (转载)警惕“番茄花园”灰色产业链

热门文章

  1. 当当悲喜交加的19年
  2. 简易单片机制作频率计
  3. android:layout_gravity=end,android layout_gravity 和gravity
  4. 你和真努力还差这几点
  5. 课设-51单片机+PM2.5+温湿度(程序+原理图+Protel仿真)
  6. LOJ2758 年轮蛋糕
  7. android 阅读pdf 文件,Android实如今线阅读PDF文件
  8. 《江畔独步寻花》教学设计
  9. 语音识别——麦克风选型
  10. FPGA云原生 Xilinx FPGA_as_a_Service 概述