【C/C++】从初始化到类型

  在 C++中,如果没有user-declared,class type会由编译器自动生成的函数有:default ctor、copy ctor、destructor和operator=(本文暂时不考虑move semantics)。当然,这些函数是在实际运行过程中调用到它们的时候再由编译器生成实际的代码再去执行,而非在编译这些class type class时直接生成在类的代码块内。

  前三个函数其实很好理解,它们分别负责一个对象的产生和消亡。其中,default ctor的特点是:函数的括号内不接收任何参数,而copy ctor的特点则是:函数的括号内只有一个参数,是当前类已经存在的对象。当然,default ctor的自动生成条件比较苛刻,一定是在当前class里面没有任何一个user-declared constructor的情况下才去生成,《C++ Primer》为这里的这个自动生成的动作起了个名字,叫做合成

  无论是哪一种,任何一个constructor要做的事情都有很多。但有一点是要注意的,构造函数本身并不会去向系统申请一块内存空间,它只是单纯地在一块已经被分配好的内存空间上做一些工作(这些内存空间的来历并不是我写作本文所关注的重点)。这些工作里有一些是它必须去做的,也有一些是我们告诉它,它再去做的。

  我们很容易想到,那些它必须去做的工作,势必和对象的产生息息相关,毕竟它的使命就是去创建一个对象。而后一部分工作被我们放在由我们自己设计的构造函数的函数体中,这一部分工作往往是构造函数已经完成了对象的创建,我们想让这个新生的对象去做的一些事情。

  在那些它必须要完成的使命中,我们最关注的事情只有一件:data member的初始化,这也是本文写作的焦点。所谓初始化,就是在每一个对象获得内存的一刻,由我们规定,或是由系统自动,去存放在这块内存上的东西。有一个很好的思想:不管多么复杂的class,也可以拆分成一个个基本类型(内置类型)。因此在正式走进class前,我们有必要对这些基本类型的变量达成一些共识。

  先回顾一下传统的面向过程的C语言,由于C语言中没有对象的概念,所以所有的东西都被称为“变量”。C语言的变量大体上分为:整型、浮点型、指针类型和聚合类型(数组和结构体)。一组值得我们留意的概念就是C语言中变量的声明定义。关于声明的正式一点的说法是这样的:向程序表明变量的类型和名字,而定义是:创建一个与名字相关联的实体,说白了就是分配内存空间。在定义时,可以为变量指定初值。

  在C中,我们几乎可以对变量的定义和声明不加以区分(不讨论函数的声明和定义):定义就是声明,声明就是定义。换言之,声明变量的同时我们也给它分配了内存空间。

  例外的情况涉及到extern关键字。考虑一组文件的情况,我们在一个文件内写出这个句子extern double pi = 3.14;,表示当前文件中我们声明并定义了变量pi,并为其初始化为3.14。当另一个文件内出现extern double pi;的时候,就意味着我们可以使用别的文件中定义的pi了。

  事实上,显式初始化extern修饰的变量会抵消extern的语义,也就是说extern double pi = 3.14;里的extern完全可以省略。因此完全可以说extern就是一种特殊的声明,不具有定义的语义。我们可以认为extern声明实际代表着一种“权限”,同样具有“权限”意味的声明是类内友元的声明。
【【【填坑】】】

  在每一名程序员学习C语言的开始,应该都会听老师讲过类似的话:“在第一次使用一个变量前,一定要将它初始化。”这并非意味着我们使用一个没有初始化的变量就一定会导致错误,它是一个优秀的编程习惯,可以帮助我们在很多复杂和庞大的工程中避免错误。

  我们后面还会再讨论来自C语言的这些数据类型。事实上,C++为了将继承自C语言的这些数据类型与自身具备面向对象特征的类型所区分开,甚至专门产生了一个概念:POD(Plain Old Data),顾名思义,又普通(Plain)又老旧(Old)的一种数据。我们上面提及的C语言所有类型,都具有这种POD性质。后文我们还会详细探讨POD的一些细节。

  这里我一定要插入《Effictive C++》的第一条:将C++视为一群语言的联邦。Scott Meyers认为,C++是四种语言所组成的联合语言,分别是:C、面向对象的C++、C++模板和STL。每一种小的语言内部,它们的语法具有高度的一致性。而一旦涉及到小语言间的交界,就要求我们做出一些规定,以便在高效编程的前提下选择最棒的处理策略。C++这门语言从出生开始,就和C语言有着数不清的纠葛,在数据类型这一部分尤为突出。形成这个思想,对理解下面的内容是很有帮助的。

  画风转回C++,《C++ Primer 5th》是我们写作本文首要的参照标准,为了避免不必要的解释,我直接罗列本书在【2.2 变量】一节需要我们明确的内容:

  1. 不区分变量对象,认为二者等价;
  2. 对象是一块内存(一块能够存储数据,并具有某种类型的内存);
  3. 所谓初始化,是指对象创建同时赋予其一个特殊值,是天生的;
  4. 初始化和赋值是两个截然不同的概念,赋值的意思是:擦除一个已经存在的对象的当前值,而以一个新值去替代(事实上,大多数operator=做的就是这样一件事情);
  5. 任何显式初始化的声明即成为定义,即有初值就是定义,没有初值有extern就是声明;
  6. 一个变量只能定义一次,但可以被多次声明(extern),这条规则是解决static成员问题的根本原则。

  当然,一旦涉及到变量,或者说对象的讨论,一个躲不开的话题就是:这个对象是否具有static类型?这个对象是否具有const类型?在接下来的讨论中,我暂且默认我所讨论的data member是一群普通的小孩,既不具有static类型,又不具有const类型。

  在涉及到更加深层的内容前,我决定首先解决一个问题,这个问题也是我写作本文的直接原因:Direct initialization & Copy initialization 到底有什么区别?

  看一下《C++ Primer 5th》的说法:

  • 直接初始化:不使用等号初始化一个变量
  • 拷贝初始化:使用等号初始化一个变量,编译器把等号右侧的值拷贝
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值