读c++primer

来源:互联网 发布:novex切削数据估算 编辑:程序博客网 时间:2024/04/28 12:42
 
关于引用:
1. 文字常量需要const reference 来容纳;
2. C++不允许声明引用数组;
 
关于数组和vector:
1. 数组不可以被另一个数组初始化,不可以被另一个数组赋值,而vector可以;
2. 任何插入操作都将增加vector的大小,而不是覆盖现有元素;
 
关于volatile:
Volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变,因此编译器不能武断地对引用这些对象的代码做优化处理。
 
关于inline:
在类内部定义的成员函数,缺省为inline,在类外定义的成员函数必须显示声明才为inline函数。在类体外定义的内联成员函数,应该被包含在含有该类定义的头文件中。
 
关于extern:
关键字extern为声明但不定义一个对象提供了一种方法。实际上,它类似于函数声明,承诺了该对象会在其他地方被定义;或者在此文本文件中的其他地方,或者在程序的其他文本文件中。Externn声明不会引起内存被分配,它可以在同一文件中或同一程序的不同文件中出现多次。Extern也可以在函数声明中指定,唯一的影响是将该声明的隐式属性“在其他地方定义”变为显式的。
 
类型安全链接(type-safe-linkage):
类型安全链接机制,通过它可以把函数参数的类型和数目编码在函数名中,用来帮助捕捉不同文件中函数声明不匹配的情况。它为文件之间的函数调用提供了类型检查手段,对于支持重载函数也是必需的。
 
关于auto_ptr:
1. 不能用一个指向“内存不是通过new表达式分配的”来初始化或者赋值auto_ptr;
2. 不能让两个auto_ptr对象拥有空闲存储区内同一对象的所有权。auto_ptr.get()与auto_ptr.release()的区别:前者得到auto_ptr指向的对象且auto_ptr同时拥有权,后者交出拥有权;
 
关于在空闲存储区创建的const对象:
1. Const对象必须被初始化(对于有缺省构造函数的class类型的对象,初始值可以省略);
2. 用new表达式返回的值作为初始值的指针必须是一个指向cosnt类型的指针;
3. 不能在空闲存储区内创建内置类项元素的const数组。原因很简单,我们不能初始化用new表达式创建的内置类型数组的元素。所有在空闲存储区内被创建的const对象都必须被初始化,而且,因为const数组不能被初始化(出了类数组),所以试图用new表达式试图创建一个内置类型的const数组会导致编译错误。
4. 定位new表达式允许程序员要求将对象分配在已经被分配好的内存中
 
关于重载:
1. 参数个数,参数类型不同,是重载;
2. 返回值类型不同,不能构成重载;(java中从JDK1.5开始支持返回值不同的函数重载)
3. 当一个参数类型为const或者volatile时,在识别函数声明是否相同时,并不考虑这两个修饰符,即看作相同;
4. 把const和volatile应用在指针或引用参数指向的类型上,则在判断函数声明是否相同时,就要考虑const和volatile修饰符,即看作不同;
5. 重载函数集合中的全部函数都应在同一域中声明。例如,一个声明为局部的函数将隐藏而不是重载一个全局域中声明的函数;
6. 用户不能在using声明中为函数指定参数表;
7. 链接指示符extern “C”只能指定重载函数集合中的一个函数;
 
关于内联函数:
1. 类体内定义的成员函数默认为inline;
2. 类体内声明为inline的成员函数在体外定义时可以省略inline关键字;
3. 内联函数必须在调用它的每个文本文件中都被定义,因此没有在类体中定义的内联成员函数必须被放在类定义出现的头文件中;
 
关于const成员函数:
1. 只有被声明为const的成员函数才能被一个const类对象调用;
2. 关键字const被放在成员函数的参数表和函数体之间;
3. 对于在类体之外定义的const成员函数,我们必须在它的定义和声明中同时指定关键字const;
4. 把一个修改数据成员的函数声明为const是非法的;
5. 把一个成员函数声明为const可以保证这个成员函数不修改类的数据成员,但是,如果该类含有指针,那么在const成员函数中就能修改指针所指的对象;编译器不会把这种修改视为错误;
6. Const成员函数可以被相同参数表的非const成员函数重载;这种情况下,类对象的常量性决定了调用哪个成员函数;
7. 构造函数和析构函数是两个例外,即使构造函数和析构函数不是const成员函数,const类对象也可以调用它们;
 
同全局对象相比,使用静态数据成员有两个优势:
1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性;
2. 可以实现信息隐蔽。静态成员可以是private成员,而全局对象不能;
 
静态数据成员的“唯一性”本质:
1. 静态数据成员的类型可以是其所属类,而非static数据成员只能被声明为该类的对象的指针或引用;
2. 静态数据成员可以被作为类成员函数的缺省实参,而非static成员不能;
3. 静态成员函数不能被声明为const或者volatile;
4. 静态成员函数中没有this指针,因此在静态成员函数中隐式或显式地引用this指针都将导致编译时刻错误;试图访问隐式引用this指针的非静态数据成员也会导致编译时刻错误;
关于union:
1. Union的成员可以被声明为公有,私有或保护的,默认是公有的;
2. Union不能有静态数据成员或是引用成员。如果一个类类型定义了构造函数,析构函数或拷贝赋值操作符,则它不能成为union的成员类型;
3. 可以为union定义成员函数,包括构造函数和析构函数;
4. 使用union的危险是,通过一个不适当的数据成员意外地获取到当前存储在union中的值,为防止这样的错误,应定义一个额外的对象,来跟踪当前被存储在union中的值的类型,这个额外对象被称为union的判别式;
 
关于嵌套类和局部类:
1. 嵌套类的构造函数不是其外围类的成员,所以我们不能讲其定义在其外围类内;亦即嵌套类的构造函数必须被定义在全局域中――该域中有其外围类的定义,当我们没有在嵌套类体内以inline形式定义嵌套类的成员函数时,我们就必须在最外围的类之外定义这些成员函数;
2. 嵌套类只能直接访问其外围类的静态成员,类型名(指的是一个typedef名字,枚举类型名或是一个类名)和枚举值(假定这些是公有的),访问外围类的非静态数据成员需要通过对象,指针或引用才能完成;
3. 同嵌套类一样,局部类可以访问的外围类域中的名字也是有限的。局部类只能访问在外围局部域中定义的类型名,静态变量以及枚举值;
 
非公有的构造函数的用处:
1. 防止用一个类的对象向该类另一个对象做拷贝;
2. 指出只有当一个类在继承层次中被用作基类,而不能直接被应用程序操纵时,构造函数才能被调用;
 
关于析构函数:
1. 析构函数不返回任何值也没有任何参数,所以不能被重载,即一个类只能有一个析构函数;
2. 析构函数主要被用来放弃在类对象的构造函数或生命期中获得的资源,如释放互斥锁或删除由操作符new分配的内存;
3. 若一个类的数据成员是按值存储的,则无需析构函数;
4. 析构函数不局限在放弃资源上。一般地,析构函数可以执行“类设计者希望在最后一次使用对象之后执行的任何操作”;
5. 析构函数被调用于函数的每一个退出点,因此当析构函数是inline的时候,应该注意尽量少用return语句,而用break代替;
 
关于类的初始化,赋值和析构:
1. 初始化阶段是隐式的,发生在构造函数被执行之前;
2. 对于类对象,在初始化和赋值之间的区别是巨大的,成员类对象应该总是在成员初始化表中被初始化,而不是在构造函数体内被赋值;
3. 对于非类数据成员的初始化或赋值,出了两个例外(即任何类型的const和引用数据成员),两者在结果和性能上都是等价的;
 
关于操作符重载:
1. 只有在左(left)操作数是该类类型的对象时,才会考虑使用作为类成员的重载操作符;
2. 四个操作符不可以重载,它们是::.*.?:  
 
关于友元:
1. 只有当一个类的定义已经被看到时,它的成员函数才能被声明为另一个类的友元;
2. 如果A类必须把B类的成员函数声明为友元,而B类必须把A类的成员函数声明为友元,那么可以把整个B类声明为A类的友元;
 
关于面向对象的一些基本概念:
1. 用基类的指针或引用操纵多个类型的能力被称为多态;
2. 在运行时刻需要解析出被调用的函数,这个解析过程被称为动态绑定(dynamic binding),缺省情况下,函数是在编译时刻被静态解析的;
3. C++中,通过一种被称为虚拟函数(virtual function)的机制来支持动态绑定;
4. 一个虚拟函数只是提供了一 个可被子类型改写的接口,但是它本身并不能通过虚拟机制被调用,这就是纯虚拟函数(pure virtual function);
5. 包含(或继承)一个或多个纯虚拟函数的类被编译器识别为抽象基类。试图创建一个抽象基类的独立类对象会导致编译时刻错误,类似的,通过虚拟机制调用纯虚拟函数也是错误的;(c++中的纯虚拟函数类似java中的抽象函数,抽象基类类似java中的抽象类);
6. 纯虚拟函数,虽然它可以通过虚拟函数机制被调用,但也可以被静态调用;
 
C++语言以下列几种方式支持多态性:
1. 通过一个隐式转换,从“派生类指针或引用”转换到“其公有基类类型的指针或引用”;
2. 通过虚拟函数机制;
3. 通过dynamic_cast和typeid操作符;
 
关于构造函数的调用顺序:
1. 基类构造函数:如果有多个基类,则构造函数的调用顺序是某类在派生类表中出现的顺序,而不是它们在成员初始化表中的顺序;
2. 成员类对象构造函数:如果有多个成员类对象,则构造函数的调用顺序是对象在类中被声明的顺序,而不是他们出现在成员初始化表中的顺序;
3. 派生类构造函数;
 
关于虚拟函数:
为了使虚拟函数的派生类实例能够改写其基类的活动实例:
1. 派生类的原型必须与基类完全匹配(检查const);
2. 返回值也必须相同,但有一个特例:派生类实例的返回值可以是基类实例返回类型的公有派生类类型;
3. 通过基类指针或引用调用派生类实例,则传给它的缺省实参是由基类指定的;
4. 虚拟机制中,虚拟函数调用的真正实例实在运行时刻根据其指针或引用指向的实际类型决定的,然而,传给虚拟函数的缺省实参却不是在运行时刻决定的,而是在编译时刻根据被调用函数的对象类型决定的;
5. 作为一般规则,建议将类层次结构的根基类(声明了一个或多个虚拟函数)的析构函数声明为虚拟的,但是,不像基类的构造函数,一般地,基类的析构函数不应该是protected;
 
原创粉丝点击