第12章 派生类
基类与派生类的构造函数与析构函数一般关系
class Base
{
public:
int a;
public:
Base(){}
~Base(){}
};
class B:public Base
{
public:
B(){}
~B(){}
};
void f()
{
B sk;
}
Base是基类, B是Base的派生类. 在一般情况下, 当实现一个派生类对象时, 会先调用基类的构造函数,再调用派生类的构造函数构建类的环境, 析构函数的调用顺序就刚好相反.
public 方式继承, 派生类会继承基类的public成员函数, 在派生类中的成员函数可以访问基类的public 成员变量, 也可以访问protected变量, 在继承方式为public的方式下, 在基类中访问控制为public的成员,在派生类中访问控制仍为public, protected的成员,访问控制仍为protected. 但是,不能访问基类的private变量. 继承方式有三种,分别为public, protected, private.
protected方式继承, 派生类的继承方式与public方式基本一样,只是在基类的访问控制为public的成员,在派生类中的访问控制会变成protected, protected的成员,仍为protected. 但是, 在这种继承方式下, 亦不允许访问基类的provate成员.
private方式继承, 继承方式与public方式基本一样, 只是在基类的访问控制为public, protected的成员,在派生类中的访问控制都变成private, 这样,如果派生类再作为基类派生出新类,则新类不能再访问祖先类的public与protected成员. 如:
class C:private Base
{
};
class D:public C
{
public:
void ff()
{
a = 0; // 出错, 因为a 为类C的private成员变量.不能被D访问
}
};
不过, protected与private继承方式很少见. 只是技术理论上讨论更多一些.
在类的继承应用中, 基类的指针可以指向派生类的, 派生类的指针不能指向基类的, 例如:
class A
{
public:
void f();
};
class B:public A
{
public:
void g();
};
int main()
{
A* ptr;
B k;
ptr = &k;
ptr->f(); // 调用的是从基类继承过来的函数
ptr->g(); // 调用的是派生类自己的函数
return 0;
}
假如是下面这样:
void tk()
{
B* p;
A kk;
p = &kk;
p->f();
p->g(); // 出错,p指向的是一个A类, 在A类里面没有定义g() 这个成员函数,这个成员函数是在派生类中定义的.
}
虚函数
虚函数, 就是在成员函数前加上virtual. 只有类的成员函数才能声明为virtual, 类外的函数不可以加上virtual. C++基于虚函数机制, 实现多态. 一个具体的例子:
class A
{
public:
virtual void display()
{ cout << "In A" << endl; }
};
class B:public A
{
public:
virtual void display() // 这里也可以不加virtual,但是加上去是个好习惯.
{ cout << "In B" << endl; }
};
class C:public A
{
public:
virtual void display()
{ cout << "In C" << endl; }
};
void f(A* p)
{
p->display();
}
int main()
{
A aa;
B bb;
C cc;
f(&aa);
f(&bb);
f(&cc);
return 0;
}
输出为:
In A
In B
In C
在程序运行时会生成一个虚函数表, 在函数f(A* p)的基类指针p会根据虚函数表调用类对象中相应的函数. 实现多态, 成员函数要求返回值, 函数名,函数参数列表都要一致. 就像调用display()函数那样. 如果去掉上面基类中display()函数前面的virtual, 则输出将会变成:
In A
In A
In A
因为B,与C继承了A的display()函数. 在函数f(A* p)中,p直接调用的是基类的display()函数. 而不调用派生类中的相应函数.