博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从零开始学C++之构造函数与析构函数(一):构造函数、析构函数、赋值与初始化、explicit关键字...
阅读量:7069 次
发布时间:2019-06-28

本文共 3153 字,大约阅读时间需要 10 分钟。

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

(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_ = 
0;
    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(
10);
    t2.Display();
    Test *t3 = 
new Test(
20);    
// new operator
    t3->Display();
    
delete t3;
    
return 
0;
}

 

 

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

可以看到构造函数是被自动调用的,且构造函数可以被重载调用;栈上的对象生存期到了会自动调用析构函数;而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(
10);
int main(
void)
{
    cout << 
"Entering main ..." << endl;
    cout << 
"Exiting main ..." << endl;
    
return 
0;
}

 

在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[
2] = {
10
20};
    Test *t2 = 
new Test(
2);
    
delete t2;
    Test *t3 = 
new Test[
2];
    
delete[] t3;
    
return 
0;
}

 

注意  Test t[2] = {

1020}; 中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(
10);     
// 带一个参数的构造函数,充当的是普通构造函数的功能
    t = 
20;         
// 将20这个整数赋值给t对象
    
// 1、调用转换构造函数将20这个整数转换成类类型 (生成一个临时对象)
    
// 2、将临时对象赋值给t对象(调用的是=运算符)
    Test t2;
    
return 
0;
}

 

 

可以看到初始化了一个临时对象,传递参数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 = 
10;        
// 等价于Test t(10); 这里的=不是运算符,表示初始化。
    t = 
20;             
// 赋值操作
    Test t2;
    t = t2;             
// 赋值操作 t.operator=(t2);
    
return 
0;
}

 

 

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

五、explicit 关键字

只提供给类的构造函数使用的关键字。

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

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

 

你可能感兴趣的文章
阿里云服务API的试用
查看>>
【MySQL 忘记密码】MySQL忘记密码怎么解决 mysql5.5 windows7
查看>>
JavaScript 的基础学习(一)
查看>>
360周鸿祎:你能不能像打游戏一样干工作?
查看>>
剑法三套,程序员也能赚大钱(3) 转
查看>>
Django 信号
查看>>
NLPIR数据语义挖掘技术为企业提供精准管理
查看>>
[Istio]Kubernetes集群部署Istio 1.0
查看>>
HTML5篇
查看>>
分页技术之PageDataSource类
查看>>
How to: Create Instances of ASP.NET User Controls Programmatically
查看>>
关于 python中的 TKinterlistbox 控件加横竖滚动条
查看>>
【leetcode】258. Add Digits
查看>>
xcode错误-第三方的东西他不支持
查看>>
结对项目:黄金点游戏
查看>>
css3之border-image
查看>>
查看静态库(.a文件)内容
查看>>
2013年Linux周刊读者投票出炉 Ubuntu、Android榜上有名
查看>>
任务02——安装 Intellj IDEA,编写一个简易四则运算小程序,并将代码提交到 GitHub...
查看>>
基于nginx的虚拟主机的配置
查看>>