双重派生 - 为什么需要铸造
Double derivation - why cast is necessary
以下代码包含多个在其中定义类的头文件:area, circle, ring, rectangle, pattern
.area
是基础类,圆是推导。ring
和rectangle
是circle
的推导,pattern
是circle
和rectangle
的推导,描述了一个彩色圆的几何图形,其中包含一个矩形的孔。类area
定义了一个变量color
由于双重派生,该变量将包含在pattern
两次中。无论如何,我希望我能以一种你可以遵循的方式陈述这个问题!
请考虑以下代码:
int main() {
area *list[8];
ring blue_ring("BLUE",5,2);
pattern blue_pattern("BLUE",30,5,5);
list[0]=&blue_ring;
list[4]=static_cast<circle *>(&blue_pattern);
return 0;
}
我不明白的是倒数第三行的演员阵容。对象blue_pattern
的类型为pattern
。指针数组list
存储指向area
类型的对象的地址。那么为什么我必须blue_pattern
转换为circle
类型的对象。 这是一本编程初学者书中的示例。它在那里说强制转换是必要的,因为对象pattern
包含来自area
两次的数据。但我不明白这个推理。
这是我试图提供最少的代码,这只是标头:
"例子0051.h"
#ifndef _AREA_
#define _AREA_
class area {
public:
area(char * n);
~area();
void getColor() const;
private:
char color[11];
};
#endif
"例子0052.h"
#ifndef _CIRCLE_
#define _CIRCLE_
#include "example0051.h"
class circle : public area {
public:
circle(char * n, float a);
~circle();
float calculateArea() const;
private:
float radius;
};
#endif
"例子0054.h">
#ifndef _RECTANGLE_
#define _RECTANGLE_
#include "example0051.h"
class rectangle : public area {
public:
rectangle(char * n, float a, float b);
~rectangle();
float calculateArea() const;
private:
float length;
float width;
};
#endif
"例子0055.h">
#ifndef _PATTERN_
#define _PATTERN_
#include "example0052.h" // circle
#include "example0054.h" // rectangle
class pattern : public circle, public rectangle {
public: pattern(char * n, float a, float b, float c);
~pattern();
float calculateArea() const;
};
#endif
请注意层次结构的外观:
area area
^ ^
| |
| |
rectangle circle
^ ^
/
/
/
pattern
因此,pattern *
可以通过两种方式投射到area *
。 编译器无法自行决定哪个版本更有效,因此它将打印错误。
添加转换为circle *
时,很清楚如何执行转换为area *
。
可能在下一步中,您将了解虚拟继承和钻石问题,但在我看来,这个例子很糟糕,这应该通过组合来解决,而不是通过多重继承来解决。
相关文章:
- 为什么派生类的好友不能使用受保护的成员?
- 为什么派生类的实例从基类调用方法?
- 为什么派生类找不到基类的类型别名?
- 为什么派生类的这个定义是非法的
- 为什么派生模板化类的函数不覆盖非模板化基类的纯虚函数?
- 为什么派生类成员的初始化值在转换为基指针时不会丢失?
- 为什么派生类可以调用基类中的成员函数
- 为什么派生类函数参数取基类函数参数的值
- 为什么派生类对象的指针数组不能声明
- 为什么派生类的大小是 8
- 为什么派生类虚函数可以调用基类虚函数?编译器如何实现
- 为什么派生类异常可以被基类捕获子句捕获
- 为什么派生类不使用基类运算符=(赋值运算符)?
- 为什么派生类无法访问非虚拟基类函数?
- 为什么派生类可以具有与基类相同的数据成员
- 为什么派生对象不只调用派生类中的重定义函数?
- 为什么派生类对象在没有参数的情况下自动调用父类构造函数
- 为什么派生类中复制/移动函数"normal"实现的行为会有所不同,具体取决于它们的定义方式?
- 为什么派生程序的退出代码在调试时会发生更改
- 为什么派生类调用基类运算符而不是它自己的运算符