part1.异常处理
1.用类去管理资源,而非显式去释放,因为异常发生的时候,析构函数一定会执行,而手动释放的代码可能不会执行。
2.catch(...)会捕获所有异常,因此应该将其置于其他catch的最后。
3.noexcept表示函数不会抛出异常。
part2.命名空间
1.多个库将名字放置在全局命名空间将引发命名空间污染。
2.每个命名空间是一个作用域,可以是不连续的。命名空间的一部分成员可以定义类,以及声名作为类的函数及对象,这部分放在头文件。命名空间成员的定义则放在源文件中。
3.模板特例化必须定义在原始模板所属的命名空间(std)。
namespace std{
template <> struct has < Sales_data>;
}
template <> struct has < Sales_data>{ … }
4.全局命名空间是隐式的。因此访问成员用 ::member_name
5.c++11引入内联命名空间,其中的名字可以被外层命名空间直接使用。一般用于版本替换时,将老版本置于非内联命名空间,新版本置于内联命名空间。
6.未命名的命名空间。在其中定义的变量将拥有静态生命周期。文件内可以不连续,但不能跨越文件。是属于文件自己的,因此两个文件中的未命名的命名空间没有关联。
namespace{...}
7.static声明是c语言的做法,c++已经取消,通过未命名的命名空间来取代。
8.命名空间可以有好几个别名。
namespace s = std;
9.using 声明:一次引入命名空间一个成员
只声明一个名字,会包含所有的重载版本。
10.using指示:所有名字都是可见的。令整个命名空间的所有内容都变得有效。
如果是跨越多个using指示的重载,则来自每个命名空间的名字都会成为候选函数集的一部分。
11.头文件只能在它的函数或者命名空间中使用using.
12.为了方便,输出运算符<<可以直接访问
13.对于接受类类型实参的函数来说,其名字查找将在实参类所属的命名空间中进行。
part3.多重继承与虚继承
1.定义:从多个基础类产生派生类的能力
2.派生类构造函数初始化所有基础类。派生类的构造函数初始值列表将实参分别传递给每个直接基础类。其中基础类的构造顺序与派生列表中基础类出现的顺序一致。与派生类构造函数初始值列表的顺序无关。
3.如果一个类从它的多个基础类中继承了相同的构造函数,则这个类必须为该构造函数定义它自己的版本:
D2(const string &s ) : Base1 (s), Base2(2) {};
D2() = default;//必须出现,why?
4.与单继承一样的操作
1)多重继承的派生类的拷贝与移动操作。
2)基于指针类型或引用类型的查找。不被自己包含的不能访问
5.派生类的对象可以传递给基础类的引用。编译器认为派生类向基础类的几种转换是一样好的。
6.多重继承下类的作用域
1)多重继承中,查找在所有基础类中同时进行。找到多个相同成员是合法的,要防止二义性,最好使用前缀限定符。
2)也可以为派生类的函数重新定义新版;
double Panda::max_weight () const{
return std::max( ZooAnimal::max_weight(), Endangered::max_weight() );
}
7.虚继承
1)目的是令某个类承诺愿意共享它的基础类。其中共享的基础类被称为虚基类。保证
钻石问题中,只出现一个虚基类子对象。
2)必须在派生类的需求出现前就完成了虚派生的操作,因此可以实现声明为虚继承。因为这样的声明不会带来什么问题。虚派生只影响从指定虚基类的派生类中进一步派生出的类,不会影响派生类本身。
3)成员可见性:如果成员被多于一个基础类覆盖,则派生类必须为该成员自定义一个
新版本。
如果B有x成员,D1,D2都是虚继承自B,如果通过D对象使用x,则
A:如果D1,D2没有x,则x是B的成员
B:如果x是B的成员,同时是D1,D2中的某一个成员,则派生类比共享虚基类B的x优先级高。否则派生类该成员没意义。。
C:如果D1,D2都有x,则产生二义性。
8.构造函数与虚继承
1)虚派生中,虚基类是由最底层的派生类初始化的。
2)含有
虚基类的对象的构造顺序与一般顺序不同:首先使用提供给最底层派生类构造函数的初始值初始化该对象的
虚基类子部分。然后按照直接基础类在派生列表中出现的次序对其一次初始化。
3)一个类可以有
多个虚基类。此时虚的子对象按照它们在派生列表中出现的顺序从左到右一次构造。如果有虚基类,则先构造虚基类。