任何在类中定义的函数自动地成为内联函数,但也可以在非类的函数前面加上 inline 关 键字使之成为内联函数,但为了使之有效,必须使函数体和声明结合在一起,否则,编译器 将他作为普通函数对待。
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声 明前面不起任何作用。如下风格的函数 Foo 不能成为内联函数:
在解决 C中宏访问 private 类成员的问题过程中,所有和预处理器宏有关的问题也随 之排除了。这是通过使宏被编译器控制来实现的。在 C中,宏的概念是作为内联函数(inline function)来实现的,而内联函数无论从哪一方面来说都是真正的函数。内联函数能够像普 通函数一样具有我们所有期望的任何行为。唯一不同的是内联函数在适当的地方像宏一样展 开。所以不需要函数调用的开销。C 语言支持函数内联,其目的是为了提高函数的执行 效率(速度)。
在 C 语言中,当程序达到一定规模以后,会遇到的一个问题是我们“用完了”函数名 称和标识符。当然并非我们真正用完了所有的函数名和标识符,而是简单的想出一个新名称 就不太容易了。更重要的是,当程序达到一定的规模之后,通常分成许多块,每一块由不同 的人或小组来构造和连接。由于所有的函数名和标识符都在同一个程序里,这就要求所有的 开发人员都必须非常小心,不要碰巧使用了相同的函数名和标识符BOB体验官网,导致冲突。
因此 C语言需要一个能完成动态内存分配和初始化工作的运算符 new,以及一个能完 成清理与释放内存工作的运算符 delete。注意 new/delete 不是库函数。
当用 new(new 的表达式)创建一个对象时,他就在堆里为对象分配内存并为这块内存 调用构造函数。
new 表达式的反面是 delete 表达式,delete 表达式首先调用析构函数,然后释放内存(经 常市调用 free()).正如 new 表达式返回一个指向对象的指针一样,delete 表达式需要一个对 象的地址。等到 delete 只用于删除由 new 创建的对象,如果用 malloc()创建一个对象,然后 用 delete 删除它,这个动作行为是未定义的,因为大多数默认的 new 和 delete 实现机制都使 用了 malloc()和 free(),所以很可能会没有调用析构函数就释放了内存。如果正在删除的对象 的指针是 0,将不发生任何事情,为此,人们经常建议,在删除指针后立即把指针赋值为 0 以免对它删除两次。对一个对象删除两次可能会产生某些问题。
标准的 C有预防这种冲突的机制:namespace 关键字。库或程序中的每一个 C定义 集被封装在一个名字空间中,如果其他的定义中有相同的名字,但它们不在同一个名字空间 就不会产生冲突。
可以用一个关键字来声明“我要使用这个名字空间中的声明和定义”。这个关键字是 “using”。所有的标准 C库都封装在一个名字空间中,即 “std”(代表 standard).
运算符与普通函数在调用时的不同之处是:对于普通函数,参数出现在圆括号内; 而对于运算符,参数出现在其左、右侧。例如
如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两个参 数的运算符叫做二元运算符。
3)从堆上分配,亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的内 存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由我们决定,使用 非常灵活,但问题也最多。
#include 有两种方式来指定文件:尖括号和双引号。 以尖括号指定文件,如下所示: #include header 用尖括号来指定文件时,预处理器是以特定的方式来寻找文件,一般用来包含开发环境 提供的库头文件,它指示编译预处理器在开发环境设定的搜索路径中查找所需的头文件。这 种设置寻找路径的机制随机器、操作系统、C实现的不同而不同。 以双引号指定文件,如下所示: #include “local.h” 用双引号时一般用来包含自己编写的头文件,它通常是从当前工作目录开始寻找,如果 文件没有找到,再到开发环境设定的路径中去查找。 包含 iostream 头文件,要用如下语句: #include iostream 预处理器会找到 iostream 头文件(通常在”include”子目录下)并把它插入头文件所在 的位置。
引用(reference)就像能自动地被编译器间接引用的常量型指针。它通常用于函数的参 数表中和函数的返回值,但也可以独立使用。
使用引用时的规则: 1) 当引用被创建时,它必须被初始化; 2) 一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用; 3) 不可能有 NULL 引用,必须确保引用是和一块合法的内存单元相关联。
默认的构造函数是如此重要,所以在一个类中没有构造函数时,编译器会自动创建一个。 但如果你没有显式地定义默认构造函数但却定义了带参构造函数,那么后者的存在就会阻止 编译器合成前者,于是你的类里就没有默认构造函数。因此,当你定义带参的构造函数时一 定要显式地定义默认构造函数。
有一些参数的值在每次函数调用时都相同,书写这样的语句会使人厌烦。C语言采用 参数的默认值使书写变得简捷(在编译时,默认值由编译器自动插入)。当然,如果函数之 间的行为差异较大,用默认参数就不合适了(对于这个问题,我们要考虑两个差异较大的函 数是否应当有相同的名字)。
把对象的初始化工作放在构造函数中,把清除工作放在析构函数中。当创建对象时,编 译器自动调用构造函数。当对象消亡时,析构函数被编译器自动调用。因此就不必担心忘记 对象的初始化和清楚工作了。
构造函数、析构函数与类同名,析构函数加前缀“~”以示区别。 构造函数与析构函数的另一个特别之处就是没有返回类型,这与返回值类型为 void 的 函数不同。析构函数不能带参数。
在 C语言中,可以用关键字 operator 加上运算符来表示函数,叫做运算符重载。例如 两个复数相加函数:
注意:不要在构造函数中做与初始化对象无关的工作,不要在析构函数中做与销毁对象无关 的工作。
对于非内部数据类型的对象而言,光用 maloc/free 无法满足动态对象的要求。对象在创 建的同时要自动执行构造函数, 对象在消亡之前要自动执行析构函数。由于 malloc/free 是
库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务 强加于 malloc/free。
如果运算符被重载为类的成员函数,那么一元运算符没有参数教程知识,二元运算符只有一个右 侧参数,因为对象自己成了左侧参数。 从语法上讲,运算符既可以定义为全局函数,也可以定义为成员函数
随着 C的不断演化,不同的编译器厂商选用了不同的文件扩展名BOB体验官网。而且,不同的操作 系统对文件名有不同的限制,特别是对文件名长度限制。结果引起了对源代码的可移植性的 限制。为了消除这些差别,标准使用的格式允许文件名长度可以大于众所周知的 8 个字符,
所谓默认构造函数就是这样的构造函数:要么它没有参数,要么所有的参数都有默认值。 当编译器需要创建一个对象而又不知任何细节时,默认的构造函数就显得非常重要。
using namespace std; 这意味着打开 std 名字空间,使它的所有名字都可用。有了这条语句,就不用担心特殊 的库组件是在一个名字空间中,因为在使用 using 指令的地方,它使名字空间在整个文件中 都是可用的。
名字空间和前面所述包含头文件的方法之间存在着相互关系。新的头文件的包含命令已 标准化了,老的包含方式里,名字空间不是语言的一部分。所以,对已存在的代码要提供向 后兼容,如果给出
为了定义内联函数,通常必须在函数定义前面放一个 inline 关键字。但这在类内部定义 内联函数时并不是必须的。任何在类内部定义的函数自动地成为内联函数。如下例:
最经常看见引用的地方是在函数参数和返回值中。当引用被用做函数参数时,在函数内 任何对引用的更改将对函数外的参数产生改变。当然,可以通过传递一个指针来做相同的事 情,但引用具有更清晰的语法。
C语言引进了三个新的关键字,用语在类中设置访问权限:public、private、protected。 他们的语法和含义从字面上就能理解。这些访问说明符只在类声明中,使用时后面必须加一 个冒号。
public 意味着在其后声明的所有成员可以被所有的人访问。相对地,private 意味着,除 了该类的内部成员函数之外,任何人都不能访问。protected 对派生类就像 public 成员一样, 对其他程序则表现得像 private。如果希望在类外部访问 private 成员就要使用友员(friend), 这个在后续章节中讲解。
初始化就是在对象创建时使用初始值直接填充对象的内存单元,因此不会有数据类型转 换等中间过程,也就不会产生临时对象;而赋值则是在对象创建好后任何时候都可以调用的 而且可以多次调用的函数,由于它调用的是“=”运算符,因此可能产生临时对象。
编译器无法预期一个程序在执行过程中会在何时创建一些什么对象,而只能根据当时的 上下文要求来创建。对象的初始化最好能够通过运行时执行一个函数来完成,而且是在对象 创建的同时,这个函数就是构造函数。同样,对象在完成其使命的时候能够通过一个函数来 销毁,这就是析构函数。
在使用默认参数时必须记住两条规则。第一,只有参数列表的后部参数才是可默认的。 也就是说,不可以在一个默认参数后面又跟一个非默认的参数。第二,一旦在一个函数调用 中开始使用默认参数,那么这个参数后面的所有参数都必须是默认的(这可以从第一条中导 出)
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运 行期间都存在。例如全局变量,static 变量。 2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行 结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但 是分配的内存容量有限。
C对 C 的最根本改变就是把函数放进了结构之中,从而产生了 C类。类将数据和函 数捆绑在一起,其中数据表示类的属性(数据成员),函数表示类的行为,也称为成员函数、 方法或者服务BOB体验官网。C提供了关键字 public、private、protected 用于声明哪些数据和函数是可 以公开访问的、私用的或者受保护(受限访问)的,这样就达到了信息隐藏的目的,即让类 仅仅公开必须让外界知道的内容,而隐藏其他内容。
拷贝构造函数采用相同类型的对象引用作为它的参数,它可以被用来从现有的类创建新 类。当用传值方式传递或返回一个对象时,编译器自动调用这个拷贝构造函数。虽然,编译 器将自动地创建一个拷贝构造函数,但是,如果认为需要为我们的类创建一个拷贝构造函数, 应该自己定义它以确保正确的操作。如果不想通过传值方式传递和返回对象,应该创建一个 私有的拷贝构造函数.
C语言允许为类定义多个构造函数,即重载构造函数,目的在于可以用不同的方式来 初始化对象。如下例:
C源程序分为两类文件。一类文件用于保存程序的声明,称为头文件。另一类文件用 于保BOB体验官网存程序的实现,称为源文件。头文件以“.h”为后缀,源文件通常以“.cpp”为后缀(也 有一些系统以“或“.cxx”为后缀)。
C编译器在扫描到一条函数调用语句时首先应当知道该函数的原型或定义,函数原型 一般都放在头文件中,函数定义则放在源文件中,当源文件用#include 包含一个头文件的时 候,编译预处理器用头文件的内容取代#include 伪指令。这就是说,头文件的所有内容最终 都会被合并到某一个或某几个源文件中。
在 C程序中,可以将功能相似的几个函数用同一个名字来表示,即函数名被重载。函 数重载便于记忆,提高了函数的易用性。这些同名函数是通过参数列表的不同而彼此区分开 来的,这里参数的不同是指参数类型、顺序、数目不同。这样当调用函数时用同样的函数名 只需用提供不同的参数。