(说实话,我一开始真没觉得构造函数这块有多重要,但是看的视频中老师却花了不少的时间去讲这块内容,本着整理了不亏的心态还是整理了一下)

1.常见的构造函数

C++的类在创建对象的时候,都会去调用构造函数,这种行为是强制的。如果在类中没去写构造函数,程序会自动为你的类创建出构造函数,然后去调用他(这个构造函数的函数体是空的,也没有形参,也不执行任何操作。);如果你已经写了构造函数,那么程序在运行的时候会去调用你写的构造函数。

构造函数是可以被重载的,一个类可以有多个重载的构造函数,创建对象时根据传递的实参来判断调用哪一个构造函数。

构造函数中又细分出默认构造函数,具体区别有三言两语不好去说明,还是直接上图比较好:

(感觉这块知识点除了学生在期末考试会考到,其他地方真能用到么)

如果看了上图还不能理解,只能放代码了

class Student
{
public:
//Student(){}//无参构造函数,默认构造函数
Student():m_strName("Jim"),m_iAge(){}//无参构造函数,默认构造函数
/*Student(string _strName,int _iAge)//无参构造函数,参数不带默认值,不是默认构造函数
{
m_strName=_strName;
m_iAge=_iAge;
}*/
Student(string _strName,int _iAge):m_strName("Jim"),m_iAge()//无参构造函数,参数带默认值,是默认构造函数
{
m_strName=_strName;
m_iAge=_iAge;
}
private:
string m_strName;
int m_iAge;
}

2.拷贝构造函数

定义格式:类名(const 类名& 变量名)

要点1:如果没有自定义的拷贝构造函数,系统会自动生成一个默认的拷贝构造函数。

要点2:当采用直接初始化或复制初始化实例化对象时系统会自动调用拷贝构造函数。

要点3:拷贝构造函数不能被重载。

要点4:拷贝构造函数在参数传递的时候也会被调用。

老惯例,上代码

class abc
{
public:
abc(){};
abc(const abc &aaa){}
private:
int a;
}
void text(abc aa3)
{ }
int main()
{
abc aa;
abc aa1 = aa;//调用拷贝构造函数
abc aa2(aa);//调用拷贝构造函数
text(aa);//调用拷贝构造函数 return ;
}

3.深拷贝和浅拷贝

其中拷贝构造函数分为浅拷贝和深拷贝,继续按照惯例上代码:

#include <iostream>
using namespace std; class text
{
public:
text():t_a(),t_b(){};
text(const text &aa):t_a(aa.t_a),t_b(aa.t_b){};//浅拷贝
private:
int t_a;
int t_b;
};
int main()
{
text a;
text b = a;
return ;
}

在上面的代码中,b就是依靠拷贝的方式初始化的,就是将 a 所在内存中的数据按照二进制位(Bit)复制到 b 所在的内存,这种默认的拷贝行为就是浅拷贝。

有浅就有深,既然有了浅拷贝,那么肯定就会有深拷贝。浅拷贝有它的缺陷,在遇到动态分配的内存、指向其他数据的指针的情况时,就会出现一些BUG,甚至会导致程序的崩溃。下面上一个本该用深拷贝却用浅拷贝的错误代码:

#include <iostream>
using namespace std; class Array
{
public:
Array()
{
m_iCount = ;
m_pArr = new int[m_iCount];
};
Array(const Array &aa)
{
m_iCount = aa.m_iCount;
m_pArr = aa.m_pArr;//此处会导致错误
};
private:
int m_iCount;
int *m_pArr;
};
int main()
{
Array a;
Array b = a;
return ;
}

在上面的代码中,a的成员变量m_pArr是个指向动态分配内存的数组的第一个地址的指针,经过浅拷贝,b的成员变量m_pArr也是指向着相同地址,这会导致修改b的数组时,a的数组也会跟着发生变化,当a销毁的时候,b的指针指向的数组则不存在,等等许多问题。所以我们需要作出一些改变来应对这种情况,于是深拷贝应运而生。

按照惯例,放出修改后的代码:

class Array
{
public:
Array()
{
m_iCount = ;
m_pArr = new int[m_iCount];
};
Array(const Array &aa)
{
m_iCount = aa.m_iCount;
m_pArr = new int[m_iCount];
for (int i; i < m_iCount; i++)
{
m_pArr[i] = aa.m_pArr[i];
}
};
private:
int m_iCount;
int *m_pArr;
};

这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝,我们必须显式地定义拷贝构造函数才能达到深拷贝的目的。

所以,什么时候用深拷贝什么时候用浅拷贝呢?

如果一个类拥有指针类型的成员变量,那么绝大部分情况下就需要深拷贝,因为只有这样,才能将指针指向的内容再复制出一份来,让原有对象和新生对象相互独立,彼此之间不受影响。如果类的成员变量没有指针,一般浅拷贝足以。

【7】学习C++之类的构造函数的更多相关文章

  1. [javase学习笔记]-7.5 构造函数须要注意的几个细节

    这一节我们简单的说几个在使用构造函数时须要注意的细节. 通过我们前几节的学习,我们对构造函数有了一个比較清楚的认识,当我们在创建对象时.我们会调用构造函数.那么我们在定义和调用构造函数时.须要注意哪些 ...

  2. 再次学习C++类之构造函数

    学习C++类,首先要说C中的结构体,虽然C++类扩展了C中的结构体,可以添加成员函数,但他们是有区别的.在结构体中,成员变量.成员函数都是公有的,而类中,一般是成员变量是私有的,成员函数是公有的,私有 ...

  3. [javase学习笔记]-7.2 构造函数与一般函数的差别

    这一节我们简单学习一下构造函数与一般函数之间的差别所在. 那么它们有什么差别呢,结合上一节,我们能够总结出下面两点差别: 第一个差别: 构造函数:对象创建时,就会调用与之相应的构造函数,对对象进行初始 ...

  4. javascript 面向对象学习(一)——构造函数

    最近在学习设计模式,找了很多资料也没有看懂,看到怀疑智商,怀疑人生,思来想去还是把锅甩到基础不够扎实上.虽然原型继承.闭包.构造函数也都有学习过,但理解得不够透彻,影响到后续提高.这次重新开始学习,一 ...

  5. C++学习基础十——子类构造函数与析构函数的执行

    1.子类构造函数的执行: 先执行父类的构造函数,再执行成员对象的构造函数,最后执行自身的构造函数. 当继承多个类时,构造函数的 执行顺序与继承时的顺序 相同,而与子类构造函数调用父类构造函数的顺序无关 ...

  6. C++学习基础六——复制构造函数和赋值操作符

    1.什么是复制构造函数 复制构造函数:是构造函数,其只有一个参数,参数类型是所属类的类型,且参数是一个const引用. 作用:将本类的成员变量赋值为引用形参的成员变量. 2.什么是赋值操作符 赋值操作 ...

  7. java学习面向对象之父子构造函数初始化

    在之前讲到java面向对象继承的时候,我们只讲到了两个比较重要的知识点,一个是父子类当中有同名的成员变量,这个时候,我们引入了super这个关键字来区分这两个同名成员变量,除此之外,我们还讲到了父子同 ...

  8. Java学习个人备忘录之构造函数&this

    构造函数 概念:构建创造对象时调用的函数. 作用:可以给对象进行初始化,创建对象都必须要通过构造函数初始化. 一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数.如果在类中定义了指 ...

  9. 我在B站学习 清华大学教授带你学习c++(进阶)构造函数

    B站av11459203的一系列视频,跳过了基础篇直接进入进阶,从此难度开始加大.这里做出一些笔记分享一下. 我是1.25速度看的..对应分P 37-38 构造函数的作用 将对象初始化为一个特定的初始 ...

随机推荐

  1. 【心得】Lattice和Xilinx工具关键特性对比(Diamond、ISE)

    [博客导航] [导航]FPGA相关 背景 由于项目需要,初次接触Diamond,发现跟之前的ISE有很多不同,记录下一些体会,供参考.按开发流程,将一些常用的特性进行对比,列举如下: IP Core管 ...

  2. pytest生成测试报告-4种方法

    1.生成resultlog文件 2.生成JunitXML文件 3.生成html测试报告 > pip install pytest-html     # 通过pip安装pytest-html 4. ...

  3. Trie树(字典树)推荐文章

    Trie树也被称为字典树,通过这个名字,可以明显知道这种树的结构:像字典一样进行查找的树(想想采用拼音法查找汉字的时候的过程,实质上就是一个逐字母匹配的过程).Trie树就是利用了这种思想构造出来的多 ...

  4. js 对象 类型转换

    对象不相等 var o = {x: 1}, p = {x: 1}; console.log(o == p); console.log(o === p); var arr1 = [], arr2 = [ ...

  5. MYSQL GTID position

    MySQL5.6 新特性之GTID - jyzhou - 博客园 http://www.cnblogs.com/zhoujinyi/p/4717951.html MySQL · 答疑释惑 · GTID ...

  6. WebApi(五)-Swagger接口文档①简单集成

    1,通过NuGet引用Swashbuckle 2,打开项目属性-->生成,勾选XML文档文件,保存 3,找到项目App_Start文件夹下WebApiConfig查找GetXmlComments ...

  7. Warning: Using a password on the command line interface can be insecure.

    [root@qttc ~]# /usr/local/mysql/bin/mysqldump  -uroot -proot db > bak.sqlWarning: Using a passwor ...

  8. vedio-js的视频插件用法

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. HTML一

    什么是前端: 前端,也称web前端对于网站来说,通常是指网站的前台部分,通俗点就是用户可以看到的部分, 浏览器.APP.应用程序的界面展现和用户交互就是前端 前端要学习那些技术:html+css+ja ...

  10. List根据对象的两个字段进行排序,并且有一个倒序

    用java8 的lambda 表达式 list.sort(Comparator.comparing(Live::getId) .thenComparing(Live::getAppId, Compar ...