Giskard

(五)继承与派生

2019-01-27

class A
{
    int i;  //基类成员
};
class B:public A //A派生了B,B继承了A,          
//B自动拥有A的成员
{
    int j;  //定义派生类的新成员
};

公有继承:

在派生类中,基类的公有成员和保护成员被继承后分别成为派生类的公有成员和保护成员。

派生类的新成员可以直接访问它们,而派生类的新成员不能直接访问基类的私有成员。在类外,派生类的对象可以访问继承下来的基类公有成员。

保护继承:class Rectangle: protected Point

在派生类中,基类的公有成员和保护成员全部成为派生类的保护成员。

派生类的新成员可以直接访问它们,而派生类的新成员不能直接访问基类的私有成员。在类外,派生类的对象不能访问基类的所有成员。

保护成员具有两面性,对外界(如主函数或非派生类的成员函数)而言是不可见的,但对于它的派生类则是可见的。

私有继承:

在派生类中,基类的公有成员和保护成员全部成为派生类的私有成员。

派生类的新成员可以直接访问它们,而派生类的新成员不能直接访问基类的私有成员。在类外,派生类的对象不能访问基类的所有成员。

将上例保护继承方式改为私有继承。运行程序,其结果与保护继承完全相同。

无论是哪种继承方式,基类的私有成员在派生类中都是不可被访问的。只能通过基类的成员函数访问基类的私有数据成员。

不能在派生类构造函数体中显式调用基类构造函数!

解决方法:

Rectangle(float x,float y,float w,float h):Point(x,y)
{
    W=w;H=h;
}
//或:
Rectangle(float x,float y,float w,float h):Point(x,y),W(w),H(h)
{}

构造函数调用顺序为:基类的构造函数→对象成员构造函数→派生类的构造函数。

析构函数调用顺序刚好相反。

派生类必须定义构造函数

当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径。这时,派生类构造函数的函数体可能为空,仅起到参数传递作用

如果在基类中既定义了无参构造函数,又定义了带参构造函数,则在定义派生类构造函数时,既可以包含基类构造函数和参数,也可以不包含基类构造函数

友元关系是不能继承的。B类是A类的友元,C类是B类的派生类,则C类和A类之间没有任何友元关系,除非C类声明A类是友元。

一个类可以从一个或者多个基类派生而来。根据派生类继承基类的个数,将继承分为单继承和多继承。

多重继承引起的二义性问题

1、 两个基类有同名成员:编译错误

2、 两个基类和派生类三者都有同名成员:默认为派生类的成员

虚基类只能继承一次

为避免对基类成员访问的二义性问题,可以将直接基类(如A、B)的共同基类(如N)设置为虚基类,这样共同基类(N)在内存中只有一个副本存在

class A
{
public: 
    A(){a=10;}
    protected:
    int a;
};
class A1:virtual public A     
{      
public:
    A1(){cout<<a<<endl;}
};
class A2:virtual public A     
{       
public:
    A2(){cout<<a<<endl;}
};
class B:A1,A2             
{
public:   
    B(){cout<<a<<endl;} 
};
int main()
{  
    B obj;
    return 0;  
}

先调用虚基类的构造函数,再调用非虚基类的构造函数。

若同一层次中包含多个虚基类,其调用顺序为定义时的顺序。

若虚基类由非虚基类派生而来,则仍按先调用基类构造函数,再调用派生类构造函数的顺序。

如果在虚基类中定义了带参数的构造函数,则要在其所有派生类(包括直接派生类或间接派生类)中,通过构造函数的初始化表对虚基类进行初始化。

class A
{ 
    A(int i){}};
class B:virtual public A
{ 
    B(int n):A(n){}};
Tags: C/C++