派生类中不同方法的多态性
Polymorphism with different methods in derived classes
在尝试学习多态性时,我对一件事感到困惑。请考虑以下情况:
存在一个基类Shape
和派生类Circle
和Square
。通过多态性,我可以在基类中将方法get_area
实现为虚函数,并在派生类Circle
和Square
中实现此功能的各个版本。
class Shape
{
public:
Shape(){}
virtual int get_area() = 0;
};
class Square: public Shape
{
public:
Square(int width, int height)
{
// stuff
}
int get_area()
{
return width*height;
}
};
class Circle: public Shape
{
public:
Circle(int radius)
{
// stuff
}
int get_area()
{
return pi*radius*radius;
}
};
int main ()
{
Shape *circle= new Circle(3);
Shape *square= new Square(4,5);
return 0;
}
但是,如果我需要在其中一个派生类中实现单个方法,例如get_radius
.如果此方法未在基类中作为虚函数进行宣传,我从编译器那里得到错误消息。但是如果我这样做,我还必须实现派生类Square
中get_radius
的方法,这没有任何意义,因为正方形没有半径。
有没有更好的方法来解决这个问题?谢谢。
如果你写
Shape *circle=new Circle(4,5);
然后尝试使用此引用来调用get_radius()
方法
circle->get_radius();
如果未在 Shape 类中声明get_radius方法(虚拟或具体),则会发生错误。发生此错误的原因是circle不是对 Circle 的引用,而是对 Shape 的引用,因此无法简单地解决方法的定义,因为 Shape 中没有定义get_radius方法。
另一方面,如果您在 Shape 类中声明了get_radius,则可以(如果它具有具体的实现)为所有类型的 Shapes 调用 get_radius,它没有多大意义。
所以正确的方法是使用对圆的引用,例如
Circle *circle=new Circle(4,5);
double r=circle->get_radius();
... //do something with r
一般来说,如果没有强制转换,你就无法做你想做的事情,这是因为运行时多态性正是这个意思:通过公共接口控制类层次结构。您的潜在Circle::get_radius()
不是界面的一部分。
如果您知道您的对象是Circle
,则一种解决方案有效:使用向下投射
Circle* ptrCircle = dynamic_cast<Circle*>(circle);
int radius = 0;
if(ptrCircle) // the cast succeeded
radius = ptrCircle->get_radius();
其中get_radius()
是仅由Circle
实现的成员函数。
注意:一般来说,对强制转换的绝对需求表明设计不好,所以最好花一些时间思考如何更好地设计你的代码。
您绝对可以将非虚拟成员函数添加到派生类中,而无需在基类中定义它们,但是不能从基类指针访问这些函数。 即:
//won't work
Shape* shapeP = new Circle();
shapeP ->get_radius();
//will work
Circle* circP = new Circle();
circP->get_radius();
您还可以将形状指针投射到您知道形状是圆形的情况,如 vsoftco 在他的答案中提到的那样
我有可能误解了你,但听起来你试图用main
打电话给circle->get_radius()
以测试它。问题是circle
实际上不是一个Circle*
对象,它是一个Shape*
。派生类的工作方式是,您可以将它们分配给类型为它们扩展/实现的任何类或接口的变量(就像您在示例中所做的那样),因为派生类包含这些基类/接口的每个成员的定义。反之则不然;正如你所说,get_radius()
对每个Shape
都没有意义.您收到错误不是因为它缺少Circle
而是因为您试图获取恰好使用Circle
函数实现的随机Shape*
的半径。
换句话说,您(作为人类)足够聪明,可以查看代码并看到circle
是一个Circle*
。编译器足够聪明,可以记住"在查找circle
函数时,使用Circle
定义的函数",但除此之外,它不知道该特定Shape*
实例与square
有何不同。据它所知,它唯一能对它们中的任何一个做的事情就是你告诉它每个Shape
都可以做的事情。
在您不关心对象的特定Shape
的情况下,这很方便 - 您所需要的只是可以为您提供区域的东西。如果您需要知道半径、宽度和高度,或者一个Shape
具有但其他人没有的任何其他属性,则需要使用具有更具体类型的变量。
看看这是否更适合您:
Circle *circle= new Circle(3);
circle->get_radius();
- 如何调用指针类型的方法(禁用多态性)?
- C ++中的方法覆盖:是编译时还是运行时多态性?
- 实现后期多态性的最佳方法
- C 中的多态性.在基类上调用继承的方法
- C++模板方法重载和具有多态性的类访问
- 派生类中不同方法的多态性
- 多态性的面向对象方法
- 为什么我需要在子类中重新声明"虚拟"方法?[C++/多态性]
- 静态多态性和方法名称 c++
- 在 C++ 中实现多态性有哪些不同的方法
- 多态性和方法重载在C++中几乎是一样的
- C++多态性模板类:调用基类方法而不是派生类
- 如何用模板方法(c++)模拟类中的多态性
- 方法重写(没有虚拟方法或指针)是否被认为是多态性的一部分
- 使用多态性打印方法.c++
- C++中的多态性:调用重写的方法
- 在继承层次结构中将方法定义为虚拟方法一次,以使多态性发挥作用
- 多态性和重写C++中类模板中的方法
- C++多态性:虚拟方法的返回类型
- 继承/多态性-调用子类的方法