C++构造函数知识点整理(C++11标准)
引言
构造函数是c++中的一个比较难的语法知识点。编程实践中,由于在很多情况下可以不显示定义构造函数,或者,虽然定义构造函数的方式并不十分适当,但是程序也能正常运行,故而并不是特别引起开发者的重视。
实际上,构造函数对C++语言十分重要,深入理解构造函数既能加深对很多C++高级语法,尤其是编译时,运行时,类的实例化和继承等概念的理解,而且能帮助我们写出更加健壮的代码。
本文从C++构造函数的概念出发,研究构造函数相关的理论和应用。包括构造函数的分类、形式、编译、运行(调用)等。在叙述的同时,辅以一些程序例子,并在一些易混淆的地方与Java、C#的构造函数进行对比。
本文中一些知识点来源于一些专业著作和网上资源,文章结尾有对这些资源的引用。
构造函数的概念的语法形式
构造函数(constructor),是类的成员函数的一种(关于构造函数属不属于类的成员函数,这里不做深究。很多资料将构造函数称为构造子,尤其在Java和C#中,将构造函数称为constructor,而将类的其它函数称作方法 - method),其作用是在定义类的实例时执行初始化操作(例如类成员变量的初始化、赋值,以及一些其它的操作)。
我们知道,函数有三要素:函数名、形参列表和返回值。对于类成员函数来说,可能还包含其它修饰符,比如访问修饰符(public,protected,private),静态修饰符(static)等。而对于构造函数来说,跟普通的成员函数相比最大的不同如下:
1. 构造函数必须与类同名;
2. 构造函数没有返回值。
3. 构造函数不能被直接显示调用。构造函数会在实例化(instantiate)类的时候被运行时调用,但不能被程序员显示调用(也可以理解为,当在代码中创建一个类的实例时,就是在调用构造函数)。
例如:
class DemoClassA{
public:
DemoClassA(){}
DemoClassA(int a):m_a(a){
}
private:
int m_a;
};
上面的代码只是一个简单的例子,可以看到,定义了两个构造函数,其中一个时无参的默认构造函数,另外一个时重载(overloaded)的含参构造函数,并用构造函数初始化值列表对类的成员变量进行了初始化。
默认构造函数,合成默认构造函数
没有形参列表的构造函数称为默认构造函数。
开发者在定义一个类时,可以选择显示定一个构造函数(或者显示定义多个重载的构造函数),也可以不显示定义构造函数。如果开发者没有显示定义任何的构造函数(包括默认构造函数),则编译器会为类生成一个默认的构造函数,称为合成默认构造函数。
如果没有特殊需求,建议开发者显示定义默认构造函数(尤其在已经定义了非默认构造函数时),原因如下:
1. 很多情况下,创建一个类的实例时,调用程序并不急于(或者不能够)对类的成员变量进行有意义的初始化,而是在运行过程中通过类似Java的SetXXX或者C#的属性的方式对成员变量赋值,因而,保留类的默认构造函数,可以方便类的使用者在初始化时无需考虑成员变量的初始化问题。除非一个类在设计时,就明确要求在其实例化时通过构造函数获得一些参数值,以执行一些特定操作(比如成员变量赋值,逻辑判断等),此时应当定义非默认构造函数,并有意不定义默认构造函数,或者定义一个私有的默认构造函数,来达到禁止利用默认构造函数实例化的目的。
2. 当类的成员变量中包含基本数据类型或者复合数据类型(例如引用或者指针),这一点上,类成员变量的初始化规则跟函数局部变量的初始化规则相同。
构造函数的定义和重载
介绍构造函数的重载规则前,先简要梳理一下普通成员函数的重载和调用规则。
构造函数由于要初始化成员变量,故而不能被修饰成const成员函数。
构造函数初始值列表、类内初始值
类内初始值是指在定义成员变量时赋给成员的初始值,包括在成员变量声明之处给的初始值,或者在类外定义的初始值。
需要注意,在C++中,初始化和赋值是两个不同的概念。
构造函数的编译和运行
C++类的构造函数编译规则(参考对比Java和C#构造函数的编译和运行规则)
编译时,编译器知道一个类实例化时所需要的内存空间大小。
很多编译器能对成员变量进行优化,故而在c语言中定义一个结构体时需要注意的字节对齐问题,C++编译器能够帮助解决。
构造函数和析构函数
析构函数可以用virtual修饰,构造函数不能
参考资料
1. C++ Primer(中文版 第5版),Stanley B. Lippman,Josée Lajoie,Barbara E. Moo 著;王刚,杨巨峰 译;叶劲峰,李云,刘未鹏 等 校
2. http://blog.csdn.net/grief_of_the_nazgul/article/details/45741849
3.
C++构造函数知识点整理(C++11标准)的更多相关文章
- 合成的默认构造函数定义为delete的一种情况(针对C++11标准)
1. 默认初始化 如果定义变量时没有指定初值,则变量会被默认初始化,此时变量被赋予了"默认值". 对于类类型的变量来说,初始化都是依靠构造函数来完成的.因此,即使定义某个类的变量( ...
- JS知识点整理(二)
前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...
- C++ Primer中文版(第5版)(顶级畅销书重磅升级全面采用最新 C++ 11标准)
C++ Primer中文版(第5版)(顶级畅销书重磅升级全面采用最新 C++ 11标准) [美]Stanley B. Lippman( 斯坦利李普曼) Josee Lajoie(约瑟拉乔伊 ) B ...
- C++11标准之右值引用(rvalue reference)
1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...
- 大数据 -- kafka学习笔记:知识点整理(部分转载)
一 为什么需要消息系统 1.解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险.许多 ...
- Python基础知识点整理(详细)
Python知识点整理(详细) 输出函数 print()可以向屏幕打印内容,或者在打开指定文件后,向文件中输入内容 输入函数 input([prompt])[prompt] 为输入的提示字符.该函数返 ...
- Flutter教程- Dart语言规范-知识点整理
Flutter教程- Dart语言知识点整理 Dart语言简介 Dart语言介绍 ① 注释的方式 ② 变量的声明 ③ 字符串的声明和使用 ④ 集合变量的声明 ⑤ 数字的处理 ⑥ 循环的格式 ⑦ 抛异常 ...
- vue前端面试题知识点整理
vue前端面试题知识点整理 1. 说一下Vue的双向绑定数据的原理 vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫 ...
- CPP全面总结(涵盖C++11标准)
OOP之类和对象 1. this指针的引入 每个成员函数都有一个额外的隐含的形参,这个参数就是this指针,它指向调用对象的地址.默认情况下,this的类型是指向类类型非常量版本的常量指针.可以表示成 ...
随机推荐
- 原!tomcat启动超时(打印了几行日志,后面没了。也不报错,处于启动状态,直到超时)
项目框架:spring+struts2+mybatis 今天优化代码,改了一堆mybatis dao和xml文件,启动项目时,就出现如标题描述的状况:打印了几行日志,后面就不打印了,也不报错,处于启动 ...
- 标准编译安装(cmake make)
为什么要编译安装?因为根据需求可以个性化定制功能. 关键是阅读cmakelist,看都有哪些依赖,都有哪些选项可用,哪些选项是自己可以配置的. 一般流程: mkdir build cd build c ...
- Python(数据库之数据类型)
一.创建表的完整语法 #[]内的可有可无,即创建表时字段名和类型是必须填写的,宽度与约束条件是可选择填写的. create table 表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[ ...
- Java排序算法总结(转载)
排序算法 平均时间复杂度 冒泡排序 O(n2) 选择排序 O(n2) 插入排序 O(n2) 希尔排序 O(n1.5) 快速排序 O(N*logN) 归并排序 O(N*logN) 堆排序 O(N*log ...
- yii根据id查询一条数据
model层 public function selectone($ag_id=''){ return $this->findBySql("SELECT * FROM agency w ...
- hibernate 一对多、多对多的配置
一对多 <class name="Question" table="questions" dynamic-insert="true" ...
- js原型 作用域
了解JavaScript原型链之前首先肯定要知道什么是原型. JavaScript中,原型是一个对象,通过原型可以实现属性的继承.既然原型是一个对象,那么任何一个对象都可以称为原型吗?是,记住它.什么 ...
- SQL生成一串随机数
SELECT RIGHT (CONVERT(VARCHAR(20),CONVERT(DECIMAL(20,15),rand())),15) AS c_random_number
- Django 函数和方法的区别
函数和方法的区别 1.函数要手动传self,方法不用传 2.如果是一个函数,用类名去调用,如果是一个方法,用对象去调用 class Foo(object): def __init__(self): s ...
- MySQL-checkpoint技术
几个知识点: 缓冲池:缓存磁盘数据,通过内存速度弥补CPU速度和磁盘速度的鸿沟. 脏页:LRU列表中被修改的页,和磁盘上的数据不一致 刷新频率:每次有脏页就刷新,开销很大.需要一种刷新机制 数据丢失: ...