1.建立普通基类Building,用来存储一座楼房的层数、房间数以及他的总平方数。建立派生类House,继承Building,并存储下面的内容:卧室与卧室的数量。另外,建立派生类Office,继承Buiding,并存储灭火器与电话的数目。
下面是自己的解答过程,不是标准答案,但是自己调试没有问题。
#include <iostream>
using namespace std;
class Building
{
private:
int Layer_number;
int room_number;
double total_square;
public:
Building(int a=0,int b=0,double c=0)//定义基类的构造函数
{
Layer_number=a;
room_number=b;
total_square=c;
}
void print()
{
cout<<"Layer_number:"<<Layer_number<<endl;
cout<<"room_number:"<< room_number<<endl;
cout<<"house's total_square:"<<total_square<<endl;
}
};
class House:public Building
{
private:
int badroom_number;
int bathroom_number;
public:
//基类定义了默认构造函数(或根本没有定义),派生类定义中可以省略对基类构造函数的调用,但是如果需求必须初始化
House(int a,int b,int x,int y,double z)
{
badroom_number=a;
bathroom_number=b;
}
void print();//这里我想使用作用域限定符消除二义性,简单实验一下(或者可以写成虚函数多态调用)
};
void House::print()
{
cout<<"The house's badroom_number:"<<badroom_number<<endl;
cout<<"The house's bathroom_number:"<<bathroom_number<<endl;
}
class Office:public Building
{
private:
int fxtinguisher_number;
int telephone_number;
public:
Office(int m,int n,int x,int y,double z):Building(x,y,z)
{
fxtinguisher_number=m;
telephone_number=n;
}
void print();
};
void Office::print()
{
cout<<"The office's telephone_number:"<<telephone_number<<endl;
cout<<"The office's fxtinguisher_number:"<<fxtinguisher_number<<endl;
}
int main()
{
House A(1,2,3,4,6.0);
A.House::print();
A.Building::print();
cout<<endl;
Office B(4,5,6,7,9.0);
B.Office::print();
B.Building::print();
return 0;
}
下面是刚刚在代码里说的基类和派生类中重名函数的另一种调用方法:虚函数的多态调用方法,刚刚上面的print()用的是消除二义性那里的作用域运算符的使用。(看书的时候这里有点混乱,虚函数的多态调用并不是在消除二义性的方法里面,但是我怎么jio的差不多应用的情况,当时他讲了还有另一种消除二义性是用的虚基类,可能我对二义性的理解不对?
书上第一个示例,讲的一个派生类有两个基类,然后重名函数产生了二义性。
奥,我可能大概知道了?
因为派生类中调用函数,可能自己里面并没有定义这个函数,他去基类里面找,结果发现自己继承的基类Base1和Base2都有这个函数,这个时候他迷茫了,站在人生的十字路口,两条一模一样路。
所以叫做二义性,采用作用域运算符给他个标签,他就知道那条路是活路那条路是死路了。
同理书上另一种二义性的情况:调用函数或数据成员在两条路的终点,即派生类的两个基类还有一个共同的基类Boss。这种情况下,这个共同的基类Boss会通过两条路径作用到派生类即在派生类中产生了两个子对象,从而导致访问的不唯一,造成二义性。
我jio得可能就是系统不会自己选择吧。
书上虚基类那段看了好几遍,大概了解到:虚基类是通过派生类继承基类的时候例如:virtual public Boss这样,加个virtual,这样就声明基类Boss是虚基类。基类Boss下面再写那些派生类,这时可能经过的不同的‘路’(也许有很多条不同的路也可能某条路会有很多层次(派生类)),建立对象时所指定的类应该是说最底层(例子中我们自己的直接派生类)的那个派生类(最后一个)就是最派生类。
写法是,定虚基类Boss的子对象必须由最派生类的构造函数通过调用虚基类的构造函数实现。
即最派生类的构造函数的初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的默认构造函数。
最派生类是相对的。(每个类,各个节点的派生类都可以创建对象)。
当建立对象的时候,虽然最派生类的所有直接基类也许都列出了对虚基类构造函数的调用,但是在执行的过程中都被忽略了,从而保证了对虚基类子对象只初始化一次。
当在构造函数的初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数被调用。
额,看着书讲的,说的好抽象,手动画个图理解下。(自己现在的理解叭,以后碰到题目理解的不对再回来改)

)
说了这么多跑远了,这是那个用虚函数写的,就改了几个小地方:
#include <iostream>
using namespace std;
class Building
{
private:
int Layer_number;
int room_number;
double total_square;
public:
Building(int a=0,int b=0,double c=0)//定义基类的构造函数
{
Layer_number=a;
room_number=b;
total_square=c;
}
virtual void print()//这次是写成虚函数多态调用。
{
cout<<"Layer_number:"<<Layer_number<<endl;
cout<<"room_number:"<< room_number<<endl;
cout<<"house's total_square:"<<total_square<<endl;
}
};
class House:public Building
{
private:
int badroom_number;
int bathroom_number;
public:
//基类定义了默认构造函数(或根本没有定义),派生类定义中可以省略对基类构造函数的调用,但是如果需求必须初始化
House(int a,int b,int x,int y,double z)
{
badroom_number=a;
bathroom_number=b;
}
void print();//这里虽然没有加virtual但是是继承过来的,也是virtual,最好写上。
};
void House::print()
{
cout<<"The house's badroom_number:"<<badroom_number<<endl;
cout<<"The house's bathroom_number:"<<bathroom_number<<endl;
}
class Office:public Building
{
private:
int fxtinguisher_number;
int telephone_number;
public:
Office(int m,int n,int x,int y,double z):Building(x,y,z)
{
fxtinguisher_number=m;
telephone_number=n;
}
virtual void print();
};
void Office::print()
{
cout<<"The office's telephone_number:"<<telephone_number<<endl;
cout<<"The office's fxtinguisher_number:"<<fxtinguisher_number<<endl;
}
int main()
{
House A(1,2,3,4,6.0);
A.print();
A.Building::print();
cout<<endl;
Office B(4,5,6,7,9.0);
B.Building::print();
B.print();
return 0;
}
运行结果:(两种都一样)

本文介绍了C++中继承和派生的概念,通过Building、House和Office类作为示例,探讨了基类和派生类中重名函数的调用方法,特别是虚函数的多态调用。文章详细解释了二义性问题,包括基类与派生类之间的二义性和多继承中的二义性,并阐述了虚基类的作用和如何解决二义性问题。此外,还展示了代码实践和运行结果。

6708

被折叠的 条评论
为什么被折叠?



