构造函数、析构函数、赋值与初始化、explicit关键字
一、构造函数、默认构造函数
(1)、构造函数
构造函数是特殊的成员函数
创建类类型的新对象,系统自动会调用构造函数
构造函数是为了保证对象的每个数据成员都被正确初始化
函数名和类名完全相同
不能定义构造函数的类型(返回类型),也不能使用void
通常情况下构造函数应声明为公有函数,一般被隐式地调用。
构造函数被声明为私有有特殊的用途,比如单例模式,以后详谈。
构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)
(2)、默认构造函数
不带参数的构造函数
如果程序中未声明,则系统自动产生出一个默认构造函数,是空函数
如果程序实现任何一个构造函数(包括拷贝构造函数),那么编译器将不再提供默认构造函数。
|
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 Test &operator=(const Test &other); ~Test(); |
|
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(int num) Test::~Test() void Test::Display() Test &Test::operator=(const Test &other) num_ = other.num_; |
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include "Test.h"
int main(void) Test t2(10); Test *t3 = new Test(20); // new operator delete t3; return 0; |
用上面的程序测试,输出为:
可以看到构造函数是被自动调用的,且构造函数可以被重载调用;栈上的对象生存期到了会自动调用析构函数;而new
operator 做了两件事,一个是创建了对象内存,一个是调用构造函数;堆上的内存需要delete
释放,做了两件事,一是调用析构函数,二是释放内存。
//我们不能调用一个构造函数但没有提供参数(实例化对象),如
A a();
//因为是有歧义的,我们也可以看成是声明了一个没有参数的函数a,返回值是类型A的一个对象
但在函数传参的时候往往可以这样写: A() // 即定义一个无名对象。
还有一个注意点,全局对象的构造先于main函数执行,如下:
|
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) |
在return 0 时全局变量的生存期也到了,故也会自动调用析构函数。
二、析构函数
函数名和类名相似(前面多了一个字符“~”)
没有返回类型
没有参数
析构函数不能被重载
如果没有定义析构函数,编译器会自动生成一个默认析构函数,其格式如下:
类名::~默认析构函数名( )
{
}
默认析构函数是一个空函数
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "Test.h"
int main(void) Test *t2 = new Test(2); Test *t3 = new Test[2]; return 0; |
注意 2] = {10, 20};
中10,20是当作参数传递给每个对象的构造函数的,如果没有对应的构造函数,比如只有2个参数的构造函数,那么编译是失败的。
实际上,构造函数和析构函数都是可以被显式调用的,只是很少这样做,可以参考这里。
三、转换构造函数
单个参数的构造函数不一定是转换构造函数
将其它类型转换为类类型
类的构造函数只有一个参数是非常危险的,因为编译器可以使用这种构造函数把参数的类型隐式转换为类类型
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "Test.h"
int main(void) t = 20; // 将20这个整数赋值给t对象 Test t2; return 0; |
可以看到初始化了一个临时对象,传递参数20,然后调用赋值运算符operator=,接着释放临时对象,最后释放的对象是已经被更改过的t 。赋值运算符的格式为:Test& Test::operator=(const Test& other);事实上如果没有自己实现,编译器也会实现一个默认的赋值运算符,做的事情跟我们现在实现的函数一样。
四、赋值与初始化的区别
在初始化语句中的等号不是运算符。
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "Test.h"
int main(void) t = 20; // 赋值操作 Test t2; return 0; |
第一条语句是初始化,后面是赋值操作,参照上面临时对象的创建销毁,赋值运算符的调用可以理解输出。
五、explicit 关键字
只提供给类的构造函数使用的关键字。
编译器不会把声明为explicit的构造函数用于隐式转换,它只能在程序代码中显示创建对象
假设在Test 类的构造函数Test(int num); 前面加上explicit 关键字,那么Test t = 10; 或者 t = 20; 这种语句都是编译不通过的,因为不允许隐式转换。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
构造函数、析构函数、赋值与初始化、explicit关键字的更多相关文章
- 21.C++- "++"操作符重载、隐式转换之explicit关键字、类的类型转换函数
++操作符重载 ++操作符分为前置++和后置++,比如: ++a; a++; ++操作符可以进行全局函数或成员函数重载 重载前置++操作符不需要参数 重载后置++操作符需要一个int类型的占位参数 ...
- C++中构造函数,拷贝构造函数和赋值函数的区别和实现
C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象 ...
- C++中的构造函数,拷贝构造函数,赋值函数
C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象 ...
- 从零开始学C++之构造函数与析构函数(一):构造函数、析构函数、赋值与初始化、explicit关键字
一.构造函数.默认构造函数 (1).构造函数 构造函数是特殊的成员函数 创建类类型的新对象,系统自动会调用构造函数 构造函数是为了保证对象的每个数据成员都被正确初始化 函数名和类名完全相同 不能定义构 ...
- C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)
在C++中,有三大函数复制控制(复制构造函数,赋值操作符,析构函数),而在C++11中,加入了移动构造函数,移动赋值操作符.我就斗胆将他们命名为六大函数好了. 一.构造函数 c++primer中说过: ...
- c++类大四个默认函数-构造函数 析构函数 拷贝构造函数 赋值构造函数
每个类只有一个析构函数和一个赋值函数,但可以有多个构造函数(包含一个拷贝构造函数,其它的称为普通构造函数).对于任意一个类A,如果不编写上述函数,C++编译器将自动为A 产生四个缺省的函数,例如: A ...
- C++ 构造函数放置默认转换explicit关键字(2)
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示: class String { String ( const char* p ); ...
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...
- C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字
原文地址:https://blog.csdn.net/shine_journey/article/details/53081523 1.在C++编码过程中,类的创建十分频繁. 简单的功能,当然不用考虑 ...
随机推荐
- Windows蓝屏dump文件查看器(转)
Windbg-分析Windows蓝屏原因利器[转]下载地址先声明下,虽然用windbg诊断蓝屏之前网络上已经有人发过教程了,但就我而言, 学会使用windbg来诊断蓝屏也算是自己的原创吧.以前看一个微 ...
- rabbitmq 连接測试
1.假设写错了host (如:factory.setHost("locathost"); )报错: Exception in thread "main" jav ...
- TCP通信粘包问题分析和解决(全)(转)
TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送 ...
- Win7下安装pip
1.首先下载setuptools,下载地址https://pypi.python.org/pypi/setuptools#downloads2.解压下载后的文件,进入命令行,将目录切换到解压后文件夹所 ...
- 第一章 在linux下python读串口 存MYSQL数据库(703N)
import MySQLdb//定义引用数据库的驱动文件 import serial import time ser = serial.Serial('/dev/ttyATH0', 115200, t ...
- mongodb,redis,memcached,mysql对比
1.性能都比较高,性能对我们来说应该都不是瓶颈总体来讲,TPS方面redis和memcache差不多,要大于mongodb 2.操作的便利性memcache数据结构单一redis丰富一些,数据操作方面 ...
- iOS:转载sqlite3
SQLITE3 使用总结 2012-08-21 13:48:28 分类: SQLite/嵌入式数据库 SQLITE3 使用总结 2009-09-16 07:36 2624人阅读 评论(10) 收藏 ...
- 数学图形(2.13)Spherical trochoid曲线
该曲线与上一节的herical cycloid球面外摆曲线 很相似,难道这是球面内摆曲线? #http://www.mathcurve.com/courbes3d/cycloidspheric/tro ...
- mysql考试总结
USE school; -- 班级表 CREATE TABLE class( cid TINYINT PRIMARY KEY AUTO_INCREMENT, caption VARCHAR(20) ) ...
- [转]Clean Code Principles: Be a Better Programmer
原文:https://www.webcodegeeks.com/web-development/clean-code-principles-better-programmer/ ----------- ...