15.2 Define Base and Derived Classes(定义基类和派生类)
基类通常应当定义一个虚析构函数,即使虚析构函数即使不工作,我们也需要。
派生类需要能够为自己的操作定义。
在基类中定义为virtual的函数期望在派生类中被重写,除了构造函数外,任意非static变量都可以成为虚成员。
尽管派生类包含了它从基类中继承来的成员,但它并不能直接初始化基类成员。
每一个类控制自己的类成员初始化。
基类首先被初始化,然后派生类按照声明顺序初始化。
派生类可以访问基类中的protected和public成员
不管基类有多少派生类,每个静态成员都只有一个示例。
假如成员是可访问的,我们能够通过静态成员来访问。
class Base{ public: static void statmem(); }; class Derived:public Base{ void f(const Derived&); }; void Derived::f(const Derived& derived_obj){ Base::statmem();//ok Derived::statmem();//ok derived_obj.statmem();//通过Derived成员访问 statmem();//通过this成员访问 }
派生类的声明和其它类的声明相同,只包含派生类,不包含派生类列表。
class B:public A;//error class B;//ok
声明的目的是让编译器知道类名的存在和它表示类型。
在我们使用一个类作为基类时,不应当仅仅声明,而不定义。
class A;//error, delared but not defined class B:public A{ ... };
新标准中,我们能够使用final来阻止一个类被下面的类作为基类。
class A{...}; class B final:A{...}; class C:B{...};//error,B不能作为基类
和内置指针相同,智能指针也支持派生到基类的转换,这意味着我们能够将派生对象类型存储在基类对象类型指针内。
不存在从基类到派生类的隐式转换。
B *b1 = &A;//error B &b2 = A;//error
我们不能从基类到派生类转换,即使基类指针/引用绑定到一个派生类对象。
B b3; A *a1 = &b3; B *b4 = a1;//error
在对象之间不存在类型转换
当我们使用一个派生类对象为一个基类对象赋值时,派生类只会赋值,拷贝,转移基类部分的对象,而派生类中的对象会被忽略。
要想理解在具有继承关系的类之间发生的类型转换,有三点非常重要:
- 从派生类向基类的类型转换只对指针或引用类型有效。
- 基类向派生类不存在隐式类型转换。
- 和任何其他成员一样,派生类向基类的类型转换也可能会由于访问权限而变得不可行。
尽管自动类型转换只对指针或引用类型有效,但是继承体系中的大多数类仍然(显式或隐式地)定义了拷贝控制成员,因此,我们通常能够将一个派生类对象拷贝、移动或赋值给一个基类对象。不过需要注意的是,这种操作只处理派生类对象的基类部分。

浙公网安备 33010602011771号