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

 

在对象之间不存在类型转换

当我们使用一个派生类对象为一个基类对象赋值时,派生类只会赋值,拷贝,转移基类部分的对象,而派生类中的对象会被忽略。

 

要想理解在具有继承关系的类之间发生的类型转换,有三点非常重要:

  • 从派生类向基类的类型转换只对指针或引用类型有效。
  • 基类向派生类不存在隐式类型转换。
  • 和任何其他成员一样,派生类向基类的类型转换也可能会由于访问权限而变得不可行。

尽管自动类型转换只对指针或引用类型有效,但是继承体系中的大多数类仍然(显式或隐式地)定义了拷贝控制成员,因此,我们通常能够将一个派生类对象拷贝、移动或赋值给一个基类对象。不过需要注意的是,这种操作只处理派生类对象的基类部分。

posted @ 2019-02-10 03:41  Hk_Mayfly  阅读(359)  评论(0)    收藏  举报