C++Primer笔记

P?)头文件中应该只定义确实需要的东西。

P37)反斜线符号必须是该行的尾字符――不允许其后面有注释或空格。同样,后继行行首的任何空格和制表符都是字符串字面值的一部分,正因如此,长字符串字面值的后继行才不会有正常的缩进。

P42)直接初始化int ival(1024);、复制初始化int ival = 1024;与赋值ival = 1024;。初始化不是赋值。初始化是指创建变量并给它赋值。赋值是指擦除对象当前值并用新值代替。

P44)在函数体外定义的变量都初始化成0,在函数体里定将的定义的内置类型不进行自动初始化。

P50)一个非const变量定义在.cpp中,可以在另外的文件中使用这个变量(默认为extern),

如:

int counter;//file1.cpp

extern int counter;//file2.cpp

const变量是定义该对象的文件的局部变量(默认为非extern),不能被其它文件访问,如:

const int counter = 3;//file1.cpp

extern int counter;//file2.cpp, error

如果把const变量定义时显示地指定为extern,就可以被其它文件访问,如:

extern const int counter = 3;//file1.cpp

extern const int counter;//file2.cpp

P52)非const引用只能绑定到与该引用同类型的对象。Const引用可以绑定到不同但相关类型的对象或绑定到右值。

P54)不能改变枚举成员的值。枚举成员本身就是一个常量表达式。

P59extern int ival = 10;有初始化式,所以是一个定义。Double fica_rate;没有extern,所以也是一个定义。同一个程序中有两个以上文件含有上述任一个定义都会导致多重定义链接错误。

P60)如果const变量不用常量表达式初始化,就不能在头文件中定义。它应该在源文件中定义,并通过在头文件中添加extern声明来共享。

P73string::size操作返回的是string::size_type类型的值。任何存储string::size操作结果的变量必须为string::size_type类型,不要把它赋给int型。string::size_type实际是某种unsigned类型,它的存储范围是int2倍。因此用int来接收可能会越界。(通过下标访问string中的字符时,也最好使用string::size_type

P75)使用’+’string对象和字符串字面值混合连接操作时,+的左右操作数至少有一个是string的。

P79vector对象(以及其它标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为vector增长的效率高,在元素值已知的情况下,最好是动态地添加元素。

P82vector的循环遍历是这样的:for(vector<int>::size_type ix = 0; ix != ivec.size(); ix++)

。注意循环结束条件用的是!=,不是规定,只是一种C++的习惯

P83vector,必须是已存在的元素才能用下标操作符进行索引,通过下标操作进行赋值时,不会添加任何元素

P86const_iterator类型的迭代器,它自身的值可以改变,但不能改变它所指向的值。不要把const_interator类型的迭代器与constiterator迭代器混淆。

P87)迭代器支持算术操作

P88)任何改变vector长度的操作都会使已存在的迭代器失效。例如,调用push_back之后,就不能再信赖指向vector的迭代器了。

P89string对象和bitset对象之间是反向转化的:string对象的最右边字符(即下标最大的那个)用来初始化bitset对象的低阶位(即下标为0的位)。

P103)如果可能的话,除非对象已存在,否则不要先定义指针。如果一定要这样,就初始化为0。编译器不能区分地址是否有效,但可以判断是否为0

P104)指针类型void*可以保存任何类型对象的地址。该指针可以(1)与另一指针比较(2)作为参数或返回值(3)给另一void*赋值。该指针不支持对它的对象操作。

P111)指向const对象的指针:const double *cptr;//cptr may point to a double that is const。这种指针常用作函数的形参,以此确保传递给函数的实际对象在函数中不因为形参而被改变。

Const指针:int *const curErr = &errNumb;//curErr is a constant pointer

P112)指针和typedef表示理解不了,记住吧

typedef(第 2.6 节)中使用指针往往会带来意外的结果。下面是一个几乎所有人刚开始时都会答错的问题。假设给出以下语句:

          typedef string *pstring;

          const pstring cstr;

请问 cstr 变量是什么类型?简单的回答是 const pstring 类型的指针。进一步问:const pstring 指针所表示的真实类型是什么?很多人都认为真正的类型是:

          const string *cstr; // wrong interpretation of const pstring cstr

也就是说,const pstring 是一种指针,指向 string 类型的 const 对象,但这是错误的。

错误的原因在于将 typedef 当做文本扩展了。声明 const pstring 时,const 修饰的是 pstring 的类型,这是一个指针。因此,该声明语句应该是把 cstr 定义为指向 string 类型对象的 const 指针,这个定义等价于:

          // cstr is a const pointer to string

          string *const cstr; // equivalent to const pstring cstr

建议:理解复杂的  const 类型的声明

阅读 const 声明语句产生的部分问题,源于 const 限定符既可以放在类型前也可以放在类型后:

          string const s1;   // s1 and s2 have same type,

          const string s2;   // they're both strings that are const

typedef const 类型定义时,const 限定符加在类型名前面容易引起对所定义的真正类型的误解:

          string s;

          typedef string *pstring;

          const pstring cstr1 = &s; // written this way the type  is obscured

          pstring const cstr2 = &s; // all three decreations are  the same type

          string *const cstr3 = &s; // they're all const pointers  to string

const 放在类型 pstring 之后,然后从右向左阅读该声明语句就会非常清楚地知道 cstr2 const pstring 类型,即指向 string 对象的 const 指针。

不幸的是,大多数人在阅读 C++ 程序时都习惯看到 const 放在类型前面。于是为了遵照惯例,只好建议编程时把 const 放在类型前面。但是,把声明语句重写为置 const 于类型之后更便于理解。

如果要表示指向const对象的指针,要怎么写呢?

P124typedef类型定义可以使指向多维数组元素的指针更容易读、写和理解。

P134)左移操作符(<<)在右边插入0以补充空位。对于右移操作符(>>),如果操作数是无符号数,则从左边开始插入0;如果操作数是有符号数,则插入符号位的副本或者0值,如何选择依据具体的实现而定。移位操作的右操作数不可以是负数,而且必须是严格小于左操作数位数的值。否则,操作的效果未定义。

P137)重载操作符与该操作符的内置版本有相同的优先级和结合性。因此移位操作符(<<>>)和输入输出操作符(<<>>)有相同的优先级(比算术操作符低,比关系、赋值、条件操作符高)和结合性(左结合)。这会影响的位操作,同样也影响输入输出操作。

P141)由于后自增操作的优先级高于解引用操作,*iter++特等效于*(iter++)

P138)只要被赋值的每个操作数都具有相同的通用类型,C++语言允许将这多个赋值操作写在一个表达式中,例如int ival, jval; ival = jval = 0;赋值操作具有右结合性,当表达式含有多个赋值操作符时,从右向左结合。

P144)用sizeof数组的结果除以sizeof其元素类型的结果,即可求出数组元素的个数。

P151)动态创建对象时,对于类类型对象,用该类的默认构造函数初始化,对于内置类型无初始化。

string *ps = new string; // initialized to empty string

     int *pi = new int;       // pi points to an uninitialized int

对于提供了默认构造函数的类类型,没有必要对其对象进行值初始化:无论程序是否明确地不初始化还是要求进行值初始化,都会自动调用其默认构造函数初始化该对象。而对于内置类型或没有定义默认构造函数的类型,采用不同的初始化方式则有显著差别。

string *ps = new string();  // initialized to empty string

     int *pi = new int();  // pi points to an int value-initialized to 0

     cls *pc = new cls();  // pc points to a value-initialized object of type cls

P156)大多数情况下数组都会自动转换为指向第一个元素的指针,以下三种情况除外:(1)数组用作取地址(&)操作符的操作数(2)数组用作sizeof操作符的操作数时(3)用数组对数组的引用进行初始化时

P159dynamic_cast:支持运行时识别指针或引用所指向的对象。const_cast:添加和删除const特性。static_cast:隐匿类型转换。Reinterpret_cast:为操作数的位模式提供较低层次的重新解释。dynamic_caststatic_cast也不应频繁使用。每次使用前,程序员一个仔细考虑是否还有其它方法。如非强转不可,一个限制强转值的作用域,并记录所有假定涉及的类型。

160)避免使用强制类型转换。Reinterpret_cast总是非常危险的。Const_cast也总是预示着设计缺陷。

P176)对于switch结构,只能在它的最后一个casedefault标号后面定义变量。如果需要为某个case定义变量,则引入块语句{},在该块语句中定义变量。

P178)在循环条件中定义的变量在每次循环里都要经历创建和撤销的过程。

P181)可以在for语句的init-statement中定义多个对象,但不管怎么样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型,如:

For(int ival = 0, *pi = ia, &ri = val; ival != size; ival++,pi++,ri++)

P188)寻找处理代码的过程与函数调用链刚好相反。抛出一个异常时,首先要搜索的是抛出异常的函数。如果没有找到匹配的 catch,则终止这个函数的执行,并在调用这个函数的函数中寻找相配的 catch。如此类推,继续按执行路径回退,直到找到适当类型的 catch 为止。

P190$ CC -DNDEBUG main.C 这样的命令行行将于在 main.c 的开头提供 #define NDEBUG 预处理命令。

P190)预处理器还定义了其余四种在调试时非常有用的常量:(1__FILE__ 文件名(2__LINE__ 当前行号(3__TIME__ 文件被编译的时间(4__DATE__ 文件被编译的日期

P191)只有 NDEBUG 未定义,assert(expr) 宏才求解条件表达式 expr。该表达式不能代码程序的逻辑。

P192dangling else(悬垂else)一个通俗术语,指出如何处理嵌套if语句中if多于else时发生的二义性问题。C++中,else总是与最近的未匹配的if配对。

P204)非const引用形参只能与完全同类型的非const对象关联。

P205void ptrswap(int *&v1, int *&v2)。形参int *&v1的定义应从右至左理解:v1 是一个引用,与指向 int 型对象的指针相关联。也就是说,v1 只是传递进 ptrswap 函数的任意指针的别名。

P206)容器类型一般不作用形参,因为调用含有普通的非引用容器形参的函数将会复制容器中的每一个元素。如果要用,应声明为引用类型,或使用容器的迭代器。

P208)如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组的实参的大小与形参的大小是否匹配
P208)和其他数组一样,多维数组以指向 0 号元素的指针方式传递。多维数组的元素本身就是数组。除了第一维以外的所有维的长度都是元素类型的一部分,必须明确指定:

void printValues(int (matrix*)[10], int rowSize);

int *matrix[10];   // array of 10 pointers

int (*matrix)[10]; // pointer to an array of 10 ints

P211C++ 中的省略符形参是为了编译使用了varargsC语言程序。对于C++程序,只能将简单数据类型传递给含有省略符形参的函数。实际上,当需要传递给省略符形参时,大多数类类型对象都不能正确地复制。省略符暂停了类型检查机制。它们的出现告知编译器,当调用函数时,可以有 0 或多个实参,而实参的类型未知。省略符形参有下列两种形式:

     void foo(parm_list, ...);

     void foo(...);

 第一种形式为特定数目的形参提供了声明。在这种情况下,只对显示声明的形参相对应的实参进行类型检查,而对于与省略符对应的实参则暂停类型检查。在第一种形式中,形参声明后面的逗号是可选的。

大部分带有省略符形参的函数都利用显式声明的参数中的一些信息,来获取函数调用中提供的其他可选实参的类型和数目。因此带有省略符的第一种形式的函数声明是最常用的。

P213)返回类型不是void的函数必须返回一个值,但main除外。如果main的最后一句都还没有返回,编译器隐式地插入return 0;

P214)千万不要返回局部变量的引用,千万不要返回指向局部对象的指针

P215)返回引用的函数返回值可以作为左值。

P216)主函数main不能调用自身

P222)内联函数应该在头文件中定义,这一点与其它函数不同。

P223)编译器隐式地将类内定义的成员函数当作内联函数。

P228main函数不能重载

P229)对于非引用的形参,const形参与非const形参是等价的。如:Record lookup(Phone);Record lookup(const Phone)是重定义。

const引用形参的函数与有非const引用形参的函数是不同的。如:Record lookup(Phone &);Record lookup(const Phone &)

P230)如果局部地声明一个函数,则该函数将屏蔽而不是重载在外层作用域中声明的同名函数。由此推论,每一个版本的重载函数都应在同一个作用域中声明。

P233)重载匹配成功条件:1. 其每个实参的匹配都不劣于其他可行函数需要的匹配。2. 至少有一个实参的匹配优于其他可行函数提供的匹配。有个CPP提交漏了,补充提交

P234)为了确定最佳匹配,编译器将实参类型到相应形参类型转换划分等级。转换等级以降序排列如下:

1. 精确匹配。实参与形参类型相同。

2. 通过类型提升实现的匹配(较小的整型提升为 int 型)

3. 通过标准转换实现的匹配

4. 通过类类型转换实现的匹配

P237)直接引用函数名等效于在函数名上应用取地址操作符,例如:

Typedef bool (*cmpFcn)(const string &, const string &);

Bool lengthCompare(const string &, const string &);

cmpFcn pf1 = lengthCompare;

cmpFcn pf2 = &lengthCompare;

P238)指向函数的指针可用于调用它所指向的函数。可以不需要使用解引用操作

符,直接通过指针调用函数,例如:

cmpFcn pf = lengthCompare;

     lengthCompare("hi", "bye"); // direct call

     pf("hi", "bye");            // equivalent call: pf1 implicitly dereferenced

     (*pf)("hi", "bye");         // equivalent call: pf1 explicitly dereferenced

P238)函数指针作为形参有两种写法:

Void useBigger(const string &, const string &, bool(const string&, const string &));

Void useBigger(const string &, const string &, bool(*)(const string&, const string &));

P238)函数可以返回指向函数的指针,但是,正确写出这种返回类型相当不容易:

     int (*ff(int))(int*, int);

阅读函数指针声明的最佳方法是从声明的名字开始由里而外理解。

要理解该声明的含义,首先观察ff(int),将 ff 声明为一个函数,它带有一个 int 型的形参。该函数返回int (*)(int*, int);它是一个指向函数的指针,所指向的函数返回 int 型并带有两个分别是int* 型和 int 型的形参。

使用 typedef 可使该定义更简明易懂:

     typedef int (*PF)(int*, int);

PF ff(int);  // ff returns a pointer to function

 P239)允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。例如:

typedef int func(int*, int);

     void f1(func); // ok: f1 has a parameter of function type

     func f2(int);  // error: f2 has a return type of function type

     func *f3(int); // ok: f3 returns a pointer to function type

P245)如果函数有基类类型的引用形参时,可以给函数传递其派生类型的对象。例如对istream&进行操作的函数,也可使用ifstream或者istringstream对象来调用。因此IO类型通过继承关联,所以可以只编写一个函数,而将它应用到三种类型的流上:控制台、磁盘文件或者字符串流。代码:

void func(ostream & t)

{

         t<<"123"<<endl;

}

 

int main()

{

         func(cout);

         ofstream f("123.txt");

         func(f);

         return 0;

}

Sstream不知道怎么用

P246IO对象不允许复制和赋值操作,所以(1)流对象不能存储在容器中(2)形参或返回类型不能是流类型,但是可以是流类型对象的指针或引用

P246)对IO对象的读写会改变它的状态,因此引用必须是非const

P248)逗号操作符的求解过程:首先计算它的每一个操作数,然后返回最右边操作数作为整个操作的结果。

P250)如果需要使用最后的输出给程序错误定位,则必须确定所有要输出的都已经输出。为了确保用户看到程序实际上处理的所有输出,最好的方法是保证所有的输出操作都显式地调用了 flush endl

P250)当输入流与输出流绑在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区。标准库将 cout cin 绑在一起,因此语句:标准库将 cout cin 绑在一起,因此语句:cin >> ival;导致 cout 关联的缓冲区被刷新。

P251)交互式系统通常应确保它们的输入和输出流是绑在一起的。这样做意味着可以保证任何输出,包括给用户的提示,都在试图读之前输出

P252IO标准库使用C风格字符串而不是C++strings类型的字符串作为文件名。假设要使用的文件名保存在string对象中,则可调用c_str成员获取 C 风格字符串。

P265)尽管不能直接将一种容器内的元素复制给另一种容器,但可以通过传递一对迭代器间接实现该功能。使用迭代器时,不要求容器类型相同。容器内的元素类型也可以不相同,只要它们相互兼容,能够将要复制的元素转换为所构建的新容器的元素类型,即可实现复制。

P267)容器元素类型必须满足以下两个约束:(1)元素类型必须支持赋值运算。(2)元素类型的对象必须可以复制。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。IO 库类型不支持复制或赋值。因此,不能创建存放 IO 类型对象的容器。

P268)必须用空格隔开两个相邻的 > 符号,以示这是两个分开的符号,否则,系统会认为 >> 是单个符号,为右移操作符,并导致编译时错误。 vector< vector<string> > lines;

P269)只有 vector deque 容器提供下面两种重要的运算集合:迭代器算术运算,以及使用除了 == != 之外的关系操作符来比较两个迭代器(== != 这两种关系运算适用于所有容器)。因为只有这种两种容器为其元素提供快速、随机的访问。

P269list 容器的迭代器既不支持算术运算,也不支持关系运算,它只提供前置和后置的自增、自减运算以及相等(不等)运算。

P270)迭代器是的end不指向最后一个元素,而是指向最后一个元素的下一个元素。此类元素范围称为左闭右开区间。

P272)无法检查迭代器是否有效,也无法通过测试来发现迭代器是否已经失效。使用迭代器时,必须留意哪些操作会使迭代器失效。通常使得要求迭代器有效的代码范围相对较短。然后在该范围内严格检查每一条语句,判断是否有元素添加或删除,从而相应地调整迭代器的值。

P274)在容器中添加元素时,系统是将元素值复制到容器里,被复制的原始值与新容器中的元素各不相关。

P277)所有的容器类型都支持关系操作符,但必须容器类型相同、元素类型相同、元素类型支持该关系操作符。

P280)使用frontback运算,如果容器为空,将会产生未定义的结果,如同使用越界的下标,编译不会检查,却会出现严重错误。

P283swap操作不会使迭代器失效。完成swap后,尽管被交换的元素已经存放在另一个容器中,但迭代器仍指向相同的元素。

P284)为了支持快速的随机访问,vector 容器的元素以连续的方式存放。在容器内添加一个元素时, vector 必须重新分配存储空间,用来存放原来的元素以及新添加的元素:存放在旧存储空间中的元素被复制到新存储空间里,接着插入新元素,最后撤销旧的存储空间。对于不连续存储元素的容器,不存在这样的内存分配问题。例如,在 listVector增加元素慢,访问元素快,list相反。

P288)如果无法确定某种应用应该采用哪种容器,则编写代码时尝试只使用vectorlist容器都提供的操作:使用迭代器而不是下标,并且避免随机访问。这样,在必要时,可以方便地从vector改为list

P289)在某些方面,可将string类型视为字符容器

P300)容器适配器与容器

 

vector

list

Deque

Queue,要求提供push_front()

不支持

支持

默认

stack

支持

支持

默认

Priority_queue,要求提供随机访问

默认

不支持

支持

 

P301)默认情况下,栈适配器建立在deque容器上。

P308)“容器元素根据键的次序排列”这一事实就是一个重要的结论:在迭代遍历关联容器时,我们可确保按键的顺序的访问元素,而与元素在容器中的存放位置完全无关。

P309map所使用的键,必须在键类型上定义严格弱排序。即必须定义<操作符。

P315map使用下标是危险的:如果该键不在map中,则会插入一个具有该键的新元素。如果不要有插入操作,应使用countfind

P319map是键-值对的集合。Set只是单纯的键的集合。当只想知道一个值是否存在时,使用set

P322map set 容器中,一个键只能对应一个实例。而 multiset multimap 类型则允许一个键对应多个实例。Multimap不支持下标运算。

P323)关联容器mapset中的元素是按顺序存放的,mulmapmulset也一样。

P337)指针的行为与作用在内置数组上的迭代器一样,因此对迭代器使用的算法也可以对数组使用。

P338)泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现。算法基于迭代器及其操作实现,而并非基于容器操作。

P375)类不能具有自身类型的数据成员,但类的数据成员可以是指向自身类型的指针或引用。

P381)形参表和函数体处于类作用域中,函数返回类型不一定在类作用域中

P388)不管数据成员是否在构造函数初始化列表中显式地初始化,它总是会在初始化阶段初始化。初始化方法就是隐式地调用数据成员的默认构造函数。如果数据成员没有默认构造函数,会出错。

P388)对于内置类型,使用初始化或赋值在结果和性能上是等价的,除了两个例外:const成员和引用。

P389)初始化的顺序就是定义成员的顺序,与初始化列表的顺序无关

P394)通过将构造函数声明为explicit来防止在需要隐式转换的上下文中使用构造函数。Explicit只用于类内部的构造函数上。

P395)除了有明显的理由要定义隐匿转换,否则,单形参构造函数应该为explicit

P397friend 关键字只能出现在类定义的内部。友元不是授予友元关系的那个类的成员,所以它们不受声明出现部分的访问控制影响。

P400static成员函数没有this指针,不能声明为constvirtual

P401static数据成员必须在类定义体外部定义(刚好一次),且在定义时初始化。

P402static数据成员可在字义体内部赋值,但是仍到在外部定义,但是定义时可以不初始化。

P409)如果一个类中有数组成员,默认的复制构造函数会复制整个数组,即复制数组中的每一个元素。

P410)为了防止复制,类必须显式地将复制构造函数声明为private。如果连友元和成员中的复制也要禁止,就声明一个private的复制构造函数但不定义。

P411)声明而不定义成员函数是合法的,但使用它会导致链接失败。

P411)如果定义了复制构造函数,也必须定义默认的构造函数。

P411)赋值操作符的重载必须定义成类的成员函数。This绑定到指向左操作操作数。

P431)重载操作符必须至少一个类类型或枚举类型的操作数

P431)重载操作符的优先级、结合性、操作数不变。但不保存求值顺序。

P435)输出操作符 << 的重载,操作符应接受 ostream& 作为第一个形参,对类类型 const 对象的引用作为第二个形参,并返回对 ostream 形参的引用。例如:

ostream& operator <<(ostream& os, const ClassType &object)

P436)输出操作符应输出对象的内容,进行最小限度的格式化,让用户自己控制输出细节。且它们不应该输出换行符。

P437)由于类的成员函数的第一个参数一定是this,因此输出操作符 <<的重载不能做为成员函数。因此,类通常将 IO操作符设为友元。

P438)使用流读入数据之前要检查。设计输入操作符时,如果可能,要确定错误恢复措施,这很重要。

P441)类的赋值操作符必须为类的成员,以便编译器知道是否需要合成一个。

P442)赋值操作符必须返回对*this的引用

P442)下标操作符必须定义为类成员函数

P443)类定义下标操作符时,一般需要定义两个版本:一个为非const成员并返回引用;另一个为const成员并返回const引用。

P443)箭头操作符(->)必须定义为成员函数。解引用操作符(*)无此要求

P445)箭头操作符不接受显示形参。必须返回指向类类型的指针,或者返回定义了自己的箭头操作符的类类型对象。

P447)自增/自减操作符会改变操作对象的状态,因此更倾向于将它们作为成员。

P447)前缘式操作符应返回被增/减对象的引用

P447)为了区分自增/自减操作符的前缀和后缀形,后缀式接受一个额外的int形参

P448)后缀操作符返回旧值,应作为值返回,不是返回引用。

P450)函数调用操作符必须声明为成员函数。定义了调用操作符的类,其对象常称为函数对象。

P454)可以定义转换操作符,完成从类类型到其它类型的转换。

P455)转换操作符在类定义体内声明,在保留字operator之后跟着转换的目标类型。对任何可作为函数返回类型的类型(除了void)都可以定义转换函数。不允许转换为数组或函数类型,可以转换成指针(数据和函数指针)以及引用类型。

P455)转换函数必须是成员函数,通常定义为const成员。不能指定返回类型,且形参必须为空。但又必须显示地返回一个指定类型的值。

P456)一个类只能定义一个类型转换。

P464)一般而言,函数调用的候选集只包括成员函数或非成员函数,不会两者都包括。而确定操作符的使用时,操作符的非成员和成员版本可能都是候选者。

P475)派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类的protected成员无访问权限。

P476)一般而言,派生类只(重)定义那些与基类不同或扩展基类行为的方面。

P477)派生类中虚函数的声明必须与基类中定义方式完全匹配。但有一个例外,返回对基类型的引用(或指针)的虚函数。派生类国的虚函数可以返回基类函数所返回类型的派生类的引用(或指针)。

P480)引用的指针的静态类型与动态类型可以不同,这是C++用以支持多态性的基石。

P481)只有成员函数中的代码才应该使用作用域操作符覆盖虚函数机制。

P482)如果基类和派生类都有一个虚函数的默认实参,使用哪个实参由调用者决定,与动态类型无关。

P484)接口继承:public继承方式,具有与基类相同的接口。实现继承:privateprotected继承方式,不继承基类的接口,但使用基类的接口。

P485class默认private继承。Struct默认public继承

P486)友元关系不能继承,基类的友元对派生类的成员没有特殊访问权限

P486)如果基类定义了static成员,则整个继承层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个static成员只有一个实例。

P490)构造函数和复制控制成员不能继承,每个类定义自己的构造函数和复制控制成员。

P491派生类构造函数的初始化列表只能初始化派生类成员,不能直接初始化继承成员。

P492)一个类只能直接初始化直接基类

P494)如果派生类定义了自己的复制构造函数,该复制构造函数一般应显式使用基类复制构造函数初始化对象的基类部分。派生类赋值操作符类似。派生类析构函数不同,它只负责清除自己的成员

P497)在基类的构造函数或析构函数中,将派生类对象作为基类类型的对象来看待。因此如果在基类的构造函数或析构函数中调用虚函数,调用的是基类定义的版本。

P498)对象、引用或指针的静态类型决定了对象能够完成的行为。

P504)句柄类存储和管理基类指针。用户通过句柄类访问继承层次的操作。句柄的用户可以获得动态行为但无须担心指针的管理。

P529)与调用函数模板形成对比,使用类模板时,必须为模板形参显示指定实参。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值