构造函数和赋值控制
构造函数和赋值控制成员不能继承。每个类都需要定义自己的这些成员。
派生类构造函数除了初始化自己的数据成员,还要初始化基类。基类部分由基类的构造函数初始化。
顺序:对于派生类对象的构造,会先执行其基类的构造函数,再构造自身另一部分。析构顺序相反。如果派生类继承自多个基类,基类的构造顺序应该为基类的定义顺序,而不是继承声明顺序。这点只是个人猜测,我没有试验。请不要作为参考。
派生类构造函数初始化列表只能初始化派生类成员,不能直接初始化继承成员。派生类构造函数通过将基类包含在构造函数初始化列表中来间接初始化继承成员。
只包含类类型或内置类型的数据成员,不含指针的类一般可以使用合成的复制控制操作。
可以进行如下操作初始化基类。
Class base{};
Class derived:public base
{
derived(const derived& d):base(d){}
};
初始化函数将派生类对象d转化为他的基类部分的引用,调用基类赋值构造函数。进行初始化。如果省略了base(d)的话,经此构造函数构造的对象的基类部分将会保持默认值(如果有的话,没有的话会出错,基类部分未初始化。)派生类自己定义的部分将是d的副本。
派生类的析构函数不负责撤销积累对象的成员。编译器重视显式调用派生类对象基类部分的析构函数。注意,对象的析构顺序与构造顺序相反:先运行派生类构造函数,然后按继承层次依次向上析构。
虚函数
C++中函数调用默认不使用动态绑定,要使用动态绑定必须:1.虚函数才可以动态绑定。成员函数默认为非虚函数。2.必须通过基类类型的引用或指针进行函数调用。
前面说过,可以使用基类类型的引用或指针绑定到派生类类型对象或基类类型对象上。所以这时,不能知道指针或引用所绑定的对象的类型。实际上,无论实际是哪种类型,编译器都将他作为基类类型的对象。这样是安全的。因为派生类都有基类子对象。
引用和指针的静态类型和动态类型可以不同,即 对象的实际类型可能不同于绑定到该对象的引用或指针的静态类型。这是C++多态性(动态绑定)的基础。
基类中定义了一个非虚函数,派生类中定义了一个同名,同形参表的函数,通过基类类型的指针,引用绑定到派生类对象上,通过指针,引用,调用的是派生类中基类部分的函数。
如果基类定义的是虚函数,派生类中定义了一个同名,同形参表的函数(可以省略virtual,但习惯上不省略),在运行时调用哪个函数,取决于运行时基类的指针或引用绑定到基类对象还是派生类对象。绑定到哪种对象上就运行各自的版本。
虚函数的使用允许通过基类指针、引用,访问派生类、基类中的同名函数。
虚函数在定义时不加virtual。
重申:通过基类指针,引用调用哪一个层次的虚函数,取决于指针,引用绑定到哪个层次。
当一个类带有虚函数时,编译系统为该类构造一个虚函数表,他是一个指针数组,存放着每个虚函数的入口地址。
在不同的继承层次中,只要与基类的虚函数名称,形参表相同,就属于一类,他们的实现部分可以不同,这是对虚函数的重定义。