C++之类的构造函数,不得不学明白的重点

一、认识构造函数

当创建一个类类型对象时,类通过一个或者几个特殊的成员函数来控制对象的初始化,这种函数就是构造函数。它的任务就是用来初始化类对象的成员的,所以当创建类对象或者类对象被创建就会调用构造函数。

构造函数的几个特点:

1.函数名和类名必须一样,没有返回值。

2.当没有显式的定义构造函数时,系统会自己生成默认的构造函数。

3.构造函数可以重载。

 1 class Date
 2 {
 3 public:
 4     Date()
 5     { }
 6     Date(int day)
 7     {
 8         _year = 1949;
 9         _month = 10;
10         _day = day;
11     }
12     void print()
13     {
14         cout << _year << "-" << _month << "-" << _day << endl;
15     }
16
17 private:
18     int _year=1990;
19     int _month;
20     int _day;
21 };

在上面的代码中,定义了一个简单的Date类类型,可以看到有显式的给出了构造函数,第一个是没有参数列表且函数不做任何事的,还有一个是有一个整型参数day的,就是当我传了一个day参数,则在函数内部把它的year和month初始化为1994和10。这样的两个构造函数就构成了重载,因为能够重载,所以在写构造函数的时候要保证只有一个缺省的构造函数。参数列表为空或者参数全缺省称为缺省构造函数。

当不传参的定义一个Date类型对象,会调用显式定义的缺省构造函数,在没有初始化列表的情况下采取类内初始化或默认初始化,上面的程序中,如果不传参,那么构建的对象的_year成员为1990,另外两个值为随机值。

牢记:

我们在没有显式的定义构造函数时,系统会自动生成一个默认构造函数。当我们定义了一些其他的构造函数时,这个类就将没有默认构造函数。所以当我们显式的定义了其他构造函数,最好把默认构造函数也显式的定义一遍。这样也有好处,就是系统生成的默认构造函数有可能执行错误的操作或者无法完成类成员的初始化(例如:有一个成员是类类型的对象且它没有缺省的构造函数)。

当我们定义的默认构造函数并不需要干什么事情,只是因为上面的情况才显式的定义它,那么此时的默认构造函数等同于系统生成的默认构造函数,那么我们可以这么定义:

Date() = default;

因为在新标准中,如果需要系统默认的行为,就可以通过在参数列表后加上=default来使编译器生成构造函数。

二、初始化列表

如下图所示,在冒号和花括号之间的代码部分称为构造函数的初始值列表,它的作用是给创建的对象的某些成员赋初值。这种是在构建对象的时候的初始化,是在对象创建成功之前完成的,和在函数体内赋值是不一样的,函数体内赋值是你的对象成员都已经创建好后对成员进行的赋值。

那么,可以看到,这种初始化并不是必须的。但是在以下几种情况时是必须进行初始化的:

1.成员是const类型。

2.成员是引用类型。

3.有一个成员是类类型的对象(且它没有缺省的构造函数)

 1 class Time
 2 {
 3 public:
 4     Time( )
 5     {
 6
 7     }
 8
 9 private:
10     int _hour;
11 };
12 class Date
13 {
14 public:
15     Date(int year=1990,int month=1,int day=1)
16         :_year(year), _month(month), _day(day), t(10)
17     { }
18     void print()
19     {
20         cout << _year << "-" << _month << "-" << _day << endl;
21     }
22 private:
23     int _year=1990;
24     int _month;
25     int _day;
26     Time t;
27 };

解释:

1.对于const和引用类型,必须要进行初始化,所以他们必须在初始化列表中进行初始化。

2.当类类型成员有缺省的构造函数时,在创建对象的时候体统会默认调用,因为不用传参。当你的构造函数不是缺省的,如果不在初始化列表中进行调用构造函数,系统就无法知道怎么调用t的构造函数,那么就无法创建t了。

如上代码中,需要在参数列表中调用t的构造函数才不会出错。

成员初始化顺序:

在上面的初始列表中,每个成员只能出现一次,因为一个变量多次初始化是无意义的。

还有重要的一点,初始化列表的顺序并不限定初始化的执行顺序。成员的初始化顺序是与类中定义的顺序保持一致。可以看看下面的初始化列表:

在这里的意思是想要用1来初始化_month,再用_month初始化_year。但其实是_year被先初始化,而此时你的_month并没有初始化,所以,最后的结果是_year是一个随机值。

所以,最好让构造函数初始值的顺序与成员声明的顺序保持一致。

时间: 2024-10-06 12:18:26

C++之类的构造函数,不得不学明白的重点的相关文章

关于peersim样例配置文件的超详细解读(新手勿喷)

相信很多兄弟一开始接触peersim,对配置文件还是有点不适应,我看了好久的样例的配置文件,一层层去找对应的文件的方法,终于好像悟懂了一点,记下来以后回顾. 贴上代码,一点点分析. 首先要说下所谓的配置文件,其实就是一个txt文件,语法也是非常简单,类似java里的给类里的变量赋值,这也正对应了配置文件的作用,配置文件,当然就是为实验的参数进行配置用的,所以配置文件的主要功能就是配置各类参数,定义一些协议类.控制类.初始化类以及一些常数. 1 # PEERSIM EXAMPLE 1 #配置文件中

Android 线程与消息 机制 15问15答

1.handler,looper,messagequeue三者之间的关系以及各自的角色? 答:MessageQueue就是存储消息的载体,Looper就是无限循环查找这个载体里是否还有消息.Handler就是创建的时候 会使用looper来构建这个消息循环. handler的主要功能就是 将一个任务切换到某个指定的线程中去执行. 2.为何android 无法在子线程更新ui? 答:都知道 更新ui 实际工作都是在viewrootimpl这个类里面去做的.他的源码里有下面这样一个函数: 1 voi

Map实现之HashMap(结构及原理)(转)

java.util包中的集合类包含 Java 中某些最常用的类.最常用的集合类是 List 和 Map.List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建.存储和操作任何类型对象元素列表.List 适用于按数值索引访问元素的情形. Map 则提供了一个更通用的元素存储方法.Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值.从概念上而言,您可以将 List 看作是具有数值键的 Map.而实际上,除了 List 和 Map 都

QtAndroid详解(1):QAndroidJniObject

Qt 5.3之后,新增了 QtAndroid 名字空间,内有下列四个方法: QAndroidJniObject AndroidActivity() int androidSdkVersion() void startActivity(const QAndroidJniObject & intent, int receiverRequestCode, QAndroidActivityResultReceiver * resultReceiver = 0) void startIntentSende

JavaScript 创建对象的七种方式

转自:xxxgitone.github.io/2017/06/10/JavaScript创建对象的七种方式/ JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以创建单个对象,显然这两种方式会产生大量的重复代码,并不适合量产.接下来介绍七种非常经典的创建对象的方式,他们也各有优缺点. 工厂模式 1 function createPerson(name, job) { 2 var o = new Object() 3 o.name = name 4 o.job

&lt;C++ - 继承02&gt; 2018-01-24

01.继承: /* 回顾上节的内容: 1.继承 1.1 吸收 父类成员 1.2 调整 父类成员(访问权限 公有 私有 受保护/隐藏) 1.3增加子类的新成员 实现更多功能 2.多继承 -->继承所有父类所有成员 菱形继承 -->虚继承 virtual 今晚 补充 复习 回顾: 继承 吸收成员 --> 对象大小 1.类中 成员变量-->对象大小只和成员变量有关 成员函数-->包含一个this指针 指向当前对象 成员 变量和函数并不在一起 static -->全局 fath

补充:JavaScript 创建对象的七种方式

JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以创建单个对象,显然这两种方式会产生大量的重复代码,并不适合量产.接下来介绍七种非常经典的创建对象的方式,他们也各有优缺点. 工厂模式 1 function createPerson(name, job) { 2 var o = new Object() 3 o.name = name 4 o.job = job 5 o.sayName = function() { 6 console.log(this.na

javascript的基础知识及面向对象和原型属性

自己总结一下javascript的基础知识,希望对大家有用,也希望大家来拍砖,毕竟是个人的理解啊 1.1 类型检查:typeof(验证数据类型是:string) var num = 123; console.log(typeof num); // 1.2 in 运算符 作用:判断指定属性是否存在于指定的对象中. 如果指定的属性存在于指定的对象中,则 in 运算符会返回 true. 语法: 属性 in 对象 返回值:true 或者 false 示例: var obj = { age: 18 };

面向对象(笔记整理)

面向对象 一.什么是面向对象 * 面向对象的定义: - 在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的   联系,这种思想就是面向对象. * 对象: - 在现实生活中存在的具体的一个事物. * 类: - 实际就是对某种类型事物的公共属性与行为的抽取.(类是一个抽象的概念,就相当   于图纸) * 对象与类的关系: - 类时对象的模板 - 汽车图纸 - 对象是类的实例 - 各种汽车 * 面向对象的核心思想: - 找适合的对象做适合的事. * 面向对象的三大特征: - 1. 封装