一、构造函数、默认构造函数

(1)、构造函数

构造函数是特殊的成员函数
创建类类型的新对象,系统自动会调用构造函数
构造函数是为了保证对象的每个数据成员都被正确初始化

函数名和类名完全相同
不能定义构造函数的类型(返回类型),也不能使用void
通常情况下构造函数应声明为公有函数,一般被隐式地调用。
构造函数被声明为私有有特殊的用途,比如单例模式,以后详谈。
构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)

(2)、默认构造函数

不带参数的构造函数
如果程序中未声明,则系统自动产生出一个默认构造函数,是空函数

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

 
#ifndef _TEST_H_


#define _TEST_H_

class Test

{


public:

    
// 如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的
    
// 默认的构造函数
    Test();

    Test(
int num);

    
void Display();

Test &
operator=(
const Test &other);

~Test();


private:

    
int num_;

};


#endif 
// _TEST_H_

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

 
#include 
"Test.h"


#include <iostream>


using 
namespace std;

// 不带参数的构造函数称为默认构造函数
Test::Test()

{

    num_ = 
;

    cout << 
"Initializing Default" << endl;

}

Test::Test(
int num)

{

    num_ = num;

    cout << 
"Initializing " << num_ << endl;

}

Test::~Test()

{

    cout << 
"Destroy " << num_ << endl;

}

void Test::Display()

{

    cout << 
"num=" << num_ << endl;

}

Test &Test::
operator=(
const Test &other)

{

    cout << 
"Test::operator=" << endl;

    
if (
this == &other)

        
return *
this;

num_ = other.num_;

    
return *
this;

}

C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

 
#include 
"Test.h"

int main(
void)

{

    Test t;

    t.Display();

Test t2(
);

    t2.Display();

Test *t3 = 
new Test(
);    
// new operator
    t3->Display();

delete t3;

return 
;

}

用上面的程序测试,输出为:

可以看到构造函数是被自动调用的,且构造函数可以被重载调用;栈上的对象生存期到了会自动调用析构函数;而new operator 做了两件事,一个是创建了对象内存,一个是调用构造函数;堆上的内存需要delete 释放,做了两件事,一是调用析构函数,二是释放内存。

还有一个注意点,全局对象的构造先于main函数执行,如下:

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

 
#include 
"Test.h"


#include <iostream>


using 
namespace std;

Test t(
);

int main(
void)

{

    cout << 
"Entering main ..." << endl;

    cout << 
"Exiting main ..." << endl;

    
return 
;

}

在return 0 时全局变量的生存期也到了,故也会自动调用析构函数。

二、析构函数

函数名和类名相似(前面多了一个字符“~”)
没有返回类型
没有参数
析构函数不能被重载
如果没有定义析构函数,编译器会自动生成一个默认析构函数,其格式如下:
类名::~默认析构函数名( )
{
}
默认析构函数是一个空函数

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 
#include 
"Test.h"

int main(
void)

{

    Test t[
] = {

};

Test *t2 = 
new Test(
);

    
delete t2;

Test *t3 = 
new Test[
];

    
delete[] t3;

return 
;

}

注意  Test t[2] = {10, 20}; 中10,20是当作参数传递给每个对象的构造函数的,如果没有对应的构造函数,比如只有2个参数的构造函数,那么编译是失败的。

实际上,构造函数和析构函数都是可以被显式调用的,只是很少这样做,可以参考这里

三、转换构造函数

单个参数的构造函数不一定是转换构造函数
将其它类型转换为类类型
类的构造函数只有一个参数是非常危险的,因为编译器可以使用这种构造函数把参数的类型隐式转换为类类型

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 
#include 
"Test.h"

int main(
void)

{

    Test t(
);     
// 带一个参数的构造函数,充当的是普通构造函数的功能

t = 
;         
// 将20这个整数赋值给t对象
    
// 1、调用转换构造函数将20这个整数转换成类类型 (生成一个临时对象)
    
// 2、将临时对象赋值给t对象(调用的是=运算符)

Test t2;

return 
;

}

可以看到初始化了一个临时对象,传递参数20,然后调用赋值运算符operator=,接着释放临时对象,最后释放的对象是已经被更改过的t 。赋值运算符的格式为:Test& Test::operator=(const Test& other);事实上如果没有自己实现,编译器也会实现一个默认的赋值运算符,做的事情跟我们现在实现的函数一样。

四、赋值与初始化的区别

在初始化语句中的等号不是运算符。

 C++ Code 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 
#include 
"Test.h"

int main(
void)

{

    Test t = 
;        
// 等价于Test t(10); 这里的=不是运算符,表示初始化。

t = 
;             
// 赋值操作

Test t2;

    t = t2;             
// 赋值操作 t.operator=(t2);

return 
;

}

第一条语句是初始化,后面是赋值操作,参照上面临时对象的创建销毁,赋值运算符的调用可以理解输出。

五、explicit 关键字

只提供给类的构造函数使用的关键字。
编译器不会把声明为explicit的构造函数用于隐式转换,它只能在程序代码中显示创建对象

假设在Test 类的构造函数Test(int num); 前面加上explicit 关键字,那么Test t = 10; 或者 t = 20; 这种语句都是编译不通过的,因为不允许隐式转换。

从零开始学C++之构造函数与析构函数(一):构造函数、析构函数、赋值与初始化、explicit关键字的更多相关文章

  1. 《从零开始学Swift》学习笔记(Day5)——我所知道的标识符和关键字

    Swift 2.0学习笔记(Day5)——我所知道的标识符和关键字   原创文章,欢迎转载.转载请注明:关东升的博客 好多计算机语言都有标识符和关键字,一直没有好好的总结,就是这样的用着,现在小小的整 ...

  2. 从零开始学C++之构造函数与析构函数(二):初始化列表(const和引用成员)、拷贝构造函数

    一.构造函数初始化列表 推荐在构造函数初始化列表中进行初始化 构造函数的执行分为两个阶段 初始化段 普通计算段 (一).对象成员及其初始化  C++ Code  1 2 3 4 5 6 7 8 9 1 ...

  3. 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换

    一.不能自动继承的成员函数 构造函数 析构函数 =运算符 二.继承与构造函数 基类的构造函数不被继承,派生类中需要声明自己的构造函数. 声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类 ...

  4. 《从零开始学Swift》学习笔记(Day 51)——扩展构造函数

    原创文章,欢迎转载.转载请注明:关东升的博客 扩展类型的时候,也可以添加新的构造函数.值类型与引用类型扩展有所区别.值类型包括了除类以外的其他类型,主要是枚举类型和结构体类型. 值类型扩展构造函数 扩 ...

  5. 《从零开始学Swift》学习笔记(Day 40)——析构函数

    原创文章,欢迎转载.转载请注明:关东升的博客 与构造过程相反,实例最后释放的时候,需要清除一些资源,这个过程就是析构过程.在析构过程中也会调用一种特殊的方法deinit,称为析构函数.析构函数dein ...

  6. 《从零开始学Swift》学习笔记(Day 39)——构造函数重载

    原创文章,欢迎转载.转载请注明:关东升的博客  构造函数作为一种特殊方法,也可以重载. Swift中构造函数可以多个,他们参数列表和返回值可以不同,这些构造函数构成重载. 示例代码如下: class ...

  7. 关东升的《从零开始学Swift》3月9日已经上架

    大家一直期盼的<从零开始学Swift>于3月9日已经上架,它是关东升老师历时8个月的呕心沥血所编著,全书600多页,此本书基于Swift 2.x,通过大量案例全面介绍苹果平台的应用开发.全 ...

  8. 关东升的《从零开始学Swift》即将出版

    大家好: 苹果2015WWDC大会发布了Swift2.0,它较之前的版本Swift1.x有很大的变化,所以我即将出版<从零开始学Swift> <从零开始学Swift>将在< ...

  9. 从零开始学 Web 之 JavaScript(四)数组

    大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...

随机推荐

  1. Sqlserver2008安装部署文档

    Sqlserver2008部署文档 注意事项: 如果你要安装的是64位的服务器,并且是新机器.那么请注意,你需要首先需要给64系统安装一个.net framework,如果已经安装此功能,请略过这一步 ...

  2. 三个创建WebStorm项目的方法

    WebStorm项目代表一个完整的解决方案和定义项目范围设置.而重点则是代码完成.代码重构.代码风格等. 因此在建立项目时,WebStorm可以通过三个方面来完成:下载远程项目.复制控制存储库项目和直 ...

  3. leetcode第27题--Implement strStr()

    Implement strStr(). Returns a pointer to the first occurrence of needle in haystack, or null if need ...

  4. leetcode第12题--Integer to Roman

    Problem: Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range ...

  5. jQuery MiniUI

    今天找到一个关于jQuery的又一个不错的UI,特此保存下.备用. http://www.miniui.com/

  6. vector成员函数解析

    vector线性集装箱,其元素颜格排序根据线性序列,和动态数组很阶段似,像阵列,它的元素被存储在连续的存储空间,这也意味着,我们不仅能够使用迭代器(iterator)访问元素,也可以用一个指针访问偏移 ...

  7. leetcode[96] Binary Tree Inorder Traversal

    给定树根root.实现中序遍历,也就是左根右. 用递归的话,很简单,左边的返回值加上root的再加上右边的就行. 我自己写的有点挫: /** * Definition for binary tree ...

  8. C#实现RSA加密和解密详解

    原文:C#实现RSA加密和解密详解 RSA加密解密源码: Code highlighting produced by Actipro CodeHighlighter (freeware) http:/ ...

  9. Codeforces 10D LCIS 找出最长公共子和产量增加这个序列 dp

    主题链接:点击打开链接 意甲冠军: 特定n长序列 给定k长序列 求LCIS并输出这个子序列 如有多解输出随意解.. = - = 敲的时候听着小曲儿pre的含义还没有想清楚,万万没想到就过了... #i ...

  10. Cocos2d-x 3.1.1开发环境

    Windows7上搭建Cocos2d-x 3.1.1开发环境   前言 现在,越来越多的公司采用Cocos2d-x 3.0来开发游戏了,但是现在这样的文章并不多,所以打算写一系列来帮助初学者快速掌握C ...