析构函数的调用顺序
先执行派生类的析构函数,对派生类新增加的成员进行清理;然后调用子对象的析构函数,对子对象进行清理;最后调用基类的析构函数,对基类进行清理
基类的构造函数不能继承,在声明派生类的时候,派生类没有把基类的构造函数继承过来,因此基类成员初始化的工作也要由派生类函数承担;执行派生类构造函数的顺序为: 1)调用基类构造函数,对基类成员初始化;2)调用子对象构造函数,对子对象数据成员初始化;3)在执行派生类构造函数,对派僧类数据成员初始化
引入虚基类的原因
当一个派生类有多个直接基类,这些直接基类又有共同的基类,那么直观上这个派生类就包含该间接基类的多份同名成员;在派生类中引用该成员的时候为了避免二义性,就必须在对象名后边添加基类名;这不仅占用了较多的空间,还增加了访问成员的困难;见下边例子的困难
#include
#include
#include
using namespace std;
class A1
{
public:
int a;
A1(int aa)
{
a = aa;
}
};
class A2
{
public:
int a;
A2(int aa)
{
a = aa;
}
};
class A3:public A1,public A2
{
public:
int b;
A3(int v1, int v2, int v3) :A1(v1), A2(v2)
{
b = v3;
}
};
int main()
{
A3 obj(1, 2, 3);
cout << obj.A1::a << endl;
return 0;
}
虚基类的作用
虚基类使得在继承共同基类的时候只留下一份成员,就是说共同的基类的对象就留下一份;
注意虚基类并不是在声明基类的时候声明的,而是在声明派生类的时候指定继承方式的时候声明的;
虚基类的构造函数,在派生类中构造函数中,以往只需要对派生类的直接基类进行初始化,但是对于虚基类的情况,最后的派生类不仅需要对直接基类进行初始化,而且需要对直接基类的共同基类进行初始化;c++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类对虚函数的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化;
使用虚基类以后派生类对象就只保留了共同基类的一份数据,可以直接用品派生类对象进行引用;
公用派生具有基类的全部功能,所有基类能够实现的功能,子类都是实现;其他类型的继承不能实现基类的全部功能;因此只用公用派生才是基类的真正子类型
注意
1) 子类对象可以给父类对象赋值,反之不成立
2) 指向基类对象的指针可以指向派生类对象,但是只是指向了派生类从基类继承过来的那部分;只能访问派生类中的基类成员,而不能访问派生类中增加的成员;见下例子
#include
#include
#include
using namespace std;
class student
{
private:
string name;
int score;
public:
student(string n, int s)
{
name = n;
score = s;
}
void display()
{
cout << "name:" << name << endl;
cout << "score:" << score << endl;
return;
}
};
class graduate:public student
{
private:
int wage;
public:
graduate(string s, int n, int w) :student(s,n)
{
wage = w;
}
void dispaly()
{
student::display();
cout << wage << endl;
return;
}
};
int main()
{
student stu("feng haojun", 100);
graduate gra("haojun", 100, 100000);
student* pt = &stu;
pt->display();
pt = &gra;
cout << endl;
pt->display();
return 0;
}
name:feng haojun
score:100
name:haojun
score:100
可见当基类对象指针指向派生类的时候,调用display函数并不是派生类中的display函数。而是基类对象中的diaplay函数;我的100k工资没有打印出来;
所以怎么样才能用这种方法把我的wage打印出来给大家看呐,就需要引用虚函数的概念这在下一篇文章介绍