一、实验目的
1. 掌握多继承程序设计
2. 掌握虚基类编程
3. 拓展学习可视化程序设计中的继承与派生应用
二、实验任务
重点:掌握虚基类的定义与实现,拓展其功能。
(1)查阅资料回答程序中思考题1~3,总结程序中的二义性问题。
(2)查阅资料回答程序中思考题4~5,改写正确的派生类D有参构造函数,完成从基类A继承过来的数据成员的初始化。
(3)查阅资料回答程序中思考题6~8,总结虚基类的特点。
(4)查阅资料,了解虚指针的概念与应用。
程序(1):没有使用虚基类
#include
using namespace std;
enum day{ one,two,three};
class A //最上层基类
{
protected:
int a;
day d;
public:
A() //无参构造函数
{
cout << "A\n";
a = 0;
d = one;
}
A(int aa,day dd) //有参构造函数
{
cout << "A\n";
a = aa;
d = dd;
}
void showA()
{
cout << "a=" << a << endl;
cout << "d=" << d << endl;
}
~A() //析构函数
{
cout << "~A\n";
}
};
class B : public A //派生类B公有继承基类A ,注意:此时没有定义A为虚基类
{
private:
string name;
public:
B() //无参构造函数, 注意:派生类对象调用构造函数初始化数据的顺序,先调用基类再调用派生类!
{
cout << "B\n";
name = " ";
}
B(int aa,day dd,string n):A(aa,dd),name(n) //有参构造函数,对从基类A继承过来的数据成员调用基类A的有参构造函数完成初始化
{
cout << "B\n";
}
~B()
{
cout << "~B\n";
}
void showB()
{
showA();
}
};
class C: public A //派生类C公有继承基类A ,注意:此时没有定义A为虚基类
{
protected:
float n[10];
public:
C() //无参构造函数//无参构造函数, 注意:派生类对象调用构造函数初始化数据的顺序,先调用基类再调用派生类!
{
cout << "C\n";
for (int i = 0; i < 10; i++)
n[i] = 0;
}
C(int aa, day dd, float nn[10]):A(aa,dd) //有参构造函数,对从基类A继承过来的数据成员调用基类A的有参构造函数完成初始化
{
cout << "C\n";
for (int i = 0; i < 10; i++)
n[i] = nn[i];
}
~C()
{
cout << "~C\n";
}
void showC()
{
showA();
}
};
struct time {
int year, month, day;
};
class D:public B,public C //派生类D公有继承基类 B,C,思考1:此时D有没有继承基类A的数据成员a、 d?从B路径继承还是从C路径继承?是否存在二义性?
{
private:
struct time bir; //结构体变量
public:
D()
{
cout << "D\n";
bir.year = bir.month = bir.day = 0;
}
D(int aa, day dd, string n, float nn[10]) :B(aa,dd,n),C(aa, dd, nn) //派生类D的有参构造函数,运行程序,思考2: D从基类A继承的数据成员a、 d有没有被初始化?
{
cout << "D\n";
bir.year = bir.month = bir.day = 0;
}
~D()
{
cout << "~D\n";
}
void showD()
{
showB();
showC();
}
};
int main()
{
float nn[] = { 1,2,3,4,5,6,7,8,9,10 };
D first(10,two,"ok",nn);
first.showD();
cout << sizeof(A)<<endl;
cout << sizeof(B)<<endl;
cout << sizeof(C)<<endl;
cout << sizeof(D)<<endl; //思考3:分析派生类D的字节数与基类AB,C的关系
return 0;
}
程序(2):使用虚基类,但有参构造函数书写不正确
#include