第一章 对象的演化
1.对象 = 特性 + 行为;
2.已存在的数据类型的设计动机:为了描述机器的存储单元;
3.一个已经习惯于寻找复杂解的、训练有素的头脑,往往会被问题的简单性难住;
第二章 收据抽象
1.面向对象程序设计中的主要活动就是向对象发消息(向对象调用成员函数)
第三章 隐藏实现
1.存取控制,C++使用关键字private,public,protected,friend 进行存取控制。
2.嵌套定义(nested class)的类对包含它的类(enclosing class)的变量的存取与定义自己
时前面的存取控制符有关,而与自己声明的位置无关。
第四章 初始化和清除
1.类的初始化和清除是如此重要,以至于Stroustrup在设计C++时定义了构造函数和析构
函数,其中前者的名字和类相同,而后者在前面加~符号。
2.上述二者都没有返回值,而且只有前者有初始化使用的参数。可以想一下,如果函数
有返回值的话,那么要么编译器知道返回值应该传递给谁,要么我们要显式的调用它
们。而这二者均是编译器自动调用的。
3.缺省构造函数:是不带任何参数的构造函数。当编译器需要创建一个对象而又不知道
任何细节时,缺省的构造函数就会被调用。所以,若一个类型中没有缺省构造函数的
话,编译器会创造一个。
第五章 函数重载和缺省参数
1. 关于函数重载,可以对比一下自然语言中我们用同一个词儿表示不同的意思,具体的解释还要参考上下文语境。重载一个很重要的应用就是构造函数。
2. 为什么不能仅根据返回值不同进行函数重载呢?因为在函数调用时可以调用一个函数而忽略它的返回值,这时编译器就无法确定我们要用哪个函数了。
3. 缺省参数:只有参数列表的后部参数才可是缺省的,意即不能在一个缺省参数后跟一个非缺省参数。
4. 为什么引入缺省函数:使函数的调用方便,可以把最不可能调整的参数放到参数表的最后;另一个原因是当需要在一个函数中增加参数时,只要增加为缺省参数即可保证调用此函数的代码没有麻烦。
第六章 输入输出流
1. C++的目标是要能特别容易的增加一种数据类型。
第七章 常量
1. 在把const和指针连起来用时,有一个技巧:在标志符的开始处读它并从里向外读。比如:const int* x: x是一个指针,它指向const int,同理:int const * x;
int* const x: x是一个const指针,指向int型变量;
2. 传递const值:变量值不会被函数修改;
代替方案:可以在函数内部用const限定参数优于在参数表里用const限定参数。
void f(int ic)
{
const int& i = ic;
i++; // illegal – compile time error
}
3. 返回const值:对于内部数据类型来说,返回值是否是常量没有关系;对于用户定义类型,那么这个函数的返回值不能是左值。
4. enum的用法,可以在类中表示常量。如下所示:
class X
{
enum { const_wanted = 0.1 };
}
之后在类的内部就可以使用const_wanted了。Ogre中有很多这种用法,以后自己写程序就不用在程序开始建全局的常量了,这个是局部的。枚举常量在编译器全部被求值。
5. 和内建数据一样,用户定义类型也可以定义一个const对象,它在对象寿命周期内不被改变。于是可以声明一个函数为const。通过这种方式告诉编译器可以为一个const对象调用这个函数。
6. this 是一个const指针。通过将this指针强制转换成non-const指针可在const函数中修改常对象成员变量。第二种方式是将变量声明成mutable。
第八章 内联函数
1. 在C++中,内联函数是为取代宏定义而存在的。任何在类中定义的函数自动成为内联函数,也可以使用inline关键字放在类外定义的函数前使之成为内联函数。
2. 内联如何有效:对于任何函数,编译器在它的符号表里放入函数类型(名字、参数类型、返回类型)。另外,编译器看到内联函数和内联函数的分析没有错时,函数代码(源程序还是汇编取决于编译器)也被放入函数表。调用时,若所有的函数类型信息符合调用上下文的话,内联函数代码会直接替换函数调用,消除了调用开销。
3. inline不支持大函数体的原因有两个:一是这时花费在函数体内的时间相对于出入函数的消耗比较大,提高效率不多;二是由于内联后会在函数每一个函数被调用的地方作代码复制,使程序变得冗余。
4. Dan Saks指出在工程中,在.h文件中定义函数体会造成接口混乱,所以他建议将所有函数定义在类外面,并使用inline关键字。
第九章 命名控制
1. static基本含义是指“位置不变的某种东西”,这里则指内存中的物理位置或文件中的可见性。在固定的地址(全局数据区)上分配/对特定的编译单元是本地的
2. 如果没有为一个预定义类型(char int float double,这些都是通过编译器预定义的C++内置类型,其它的都是用户自定义类型)的static 变量初始化,编译器会将其初始化为0;
3. 全局变量的构造函数在main()之前就被执行。
4. 函数后跟随throw()是为了告诉编译器这个函数有可能会抛出异常。
5. extern 和 static:前者对所有的编译单元都是可见的,而后者只是局部变量。
全局变量:int a = 0;隐含为静态存储类,所以前述定义和extern int a = 0;是等价的。
6. auto 和register:前者告诉编译器这是一个局部变量,后者告诉编译器这是一个会经常用到的变量,最好把它一直保存在寄存器中,做代码优化时使用。
7. static成员变量:定义必须出现在类的外部而且只能定义一次,因此通常放到类的实现文件中。即我们通常所说的cpp文件的开头;当然也可以在定义文件的最后;
static成员函数:可以调用静态成员变量,不能调用非静态成员变量;而非静态成员函数既可以调用静态成员函数又可以调用非静态成员函数。
想一下:静态成员函数是属于类的,而不属于某个对象,如果调用成员变量/函数,调用谁的呢?既然非静态成员函数可以调用静态成员变量,那么就可以调用静态成员函数。
8. nested class can have static data members; local class cannot have static data members.
9. static const 代替之前的enum,因为enum的常量用法使枚举丧失了本来的作用,而且只能定义整型值。
10. 通常当前对象的地址this被隐含的传递到被调用的函数,但静态成员函数没有this,所以他无法访问一般的成员函数。
11. C++编译器会将函数名字变成_f_int_int之类的东西以支持函数重载,但是c编译器通常不会这么做,内部名通常为f。这样连接器将无法解决C++对f()的调用。extern “C” float f(int, int) 这就告诉编译器f()是C连接,这样就不会转换函数名。如果头文件中都是声明的话,可以通过extern “C” { #include “cHeader.h” }实现;
《C++编程思想》