引言

构造函数是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标准)的更多相关文章

  1. 合成的默认构造函数定义为delete的一种情况(针对C++11标准)

    1. 默认初始化 如果定义变量时没有指定初值,则变量会被默认初始化,此时变量被赋予了"默认值". 对于类类型的变量来说,初始化都是依靠构造函数来完成的.因此,即使定义某个类的变量( ...

  2. JS知识点整理(二)

    前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...

  3. C++ Primer中文版(第5版)(顶级畅销书重磅升级全面采用最新 C++ 11标准)

    C++ Primer中文版(第5版)(顶级畅销书重磅升级全面采用最新 C++ 11标准) [美]Stanley B. Lippman( 斯坦利李普曼)  Josee Lajoie(约瑟拉乔伊 )  B ...

  4. C++11标准之右值引用(rvalue reference)

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...

  5. 大数据 -- kafka学习笔记:知识点整理(部分转载)

    一 为什么需要消息系统 1.解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险.许多 ...

  6. Python基础知识点整理(详细)

    Python知识点整理(详细) 输出函数 print()可以向屏幕打印内容,或者在打开指定文件后,向文件中输入内容 输入函数 input([prompt])[prompt] 为输入的提示字符.该函数返 ...

  7. Flutter教程- Dart语言规范-知识点整理

    Flutter教程- Dart语言知识点整理 Dart语言简介 Dart语言介绍 ① 注释的方式 ② 变量的声明 ③ 字符串的声明和使用 ④ 集合变量的声明 ⑤ 数字的处理 ⑥ 循环的格式 ⑦ 抛异常 ...

  8. vue前端面试题知识点整理

    vue前端面试题知识点整理 1. 说一下Vue的双向绑定数据的原理 vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫 ...

  9. CPP全面总结(涵盖C++11标准)

    OOP之类和对象 1. this指针的引入 每个成员函数都有一个额外的隐含的形参,这个参数就是this指针,它指向调用对象的地址.默认情况下,this的类型是指向类类型非常量版本的常量指针.可以表示成 ...

随机推荐

  1. 报错:Cannot remove entries from nonexistent file c:\program files\anaconda3\lib\site-packages\easy-install.pth

    Outline 这两天通过“掘金量化终端”跑模型策略,之前装好环境一直ok,可以顺畅的Running~ 下午重装了下 Anaconda,刚才跑的时候提示 缺少“gm”模块 (掘金量化必须包): 就按照 ...

  2. Kotlin开发Android笔记

    外国人写的一个天气预报的例子,最后有源码下载地址,初学者可以研读一下 http://blog.csdn.net/true100/article/category/6257988 1:Kotlin介绍及 ...

  3. eclipse导入项目,项目名出现红叉的情况(修改版)

    转至:http://blog.csdn.net/niu_hao/article/details/17440247 今天用eclipse导入同事发给我的一个项目之后,项目名称上面出现红叉,但是其他地方都 ...

  4. Linux一键安装web环境全攻略(阿里云ECS服务器)

    摘自阿里云服务器官网,此处 一键安装包下载: 点此下载 安装须知 1.此安装包可在阿里云所有linux系统上部署安装,此安装包包含的软件及版本为: nginx:1.0.15.1.2.5.1.4.4 a ...

  5. ES6简单入门

    let let命令用来声明块级作用域. 以前的JavaScript只有全局作用域和函数作用域, 没有块级作用域. // 示例1: if (1) { var a = "hello"; ...

  6. C# 事件浅析

    前言 对于搞.net的朋友来说,经常会遇到关于事件和委托的问题:事件与委托有什么关系?事件的本质是什么?委托的本质又是什么?由于.net 做了大量的封装,对于初学者,这两个概念确实不怎么好理解.事件是 ...

  7. CodeMatic动软自动生成Nhibernate

    前两天调查了下自动生成工具MyGeneration和codesmith前一个版本已经不更新了后面一个太高级生成 的代码包含了太多东西,没整明白.不过生成的xmlmapping很强大.所以干脆整合一下c ...

  8. html-2, a img ul li ol dl dt dd 标签与列表标签的简单使用

    <!-- a:  a{ /*清除a标签的下划线*/ text-decoration: none; }  (1)超链接 href 超链接的地址 target: _self 默认 在当前中打开链接地 ...

  9. c语言单元测试框架--CuTest

    1.简介 CuTest是一款微小的C语言单元测试框,是我迄今为止见到的最简洁的测试框架之一,只有2个文件,CuTest.c和CuTest.h,全部代码加起来不到一千行.麻雀虽小,五脏俱全,测试的构建. ...

  10. js自执行函数&扩展方法

    我们通常将JS代码写在一个单独的JS文件中,然后在页面中引入该文件.但是,有时候引入后会碰到变量名或函数名与其它JS代码冲突的问题.那么如何解决这个问题呢?作用域隔离.在JS中,作用域是通过函数来划分 ...