在尝试学习多态时,我对一件事感到困惑。请考虑以下情况:
存在基类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
,该怎么办?如果此方法不作为基类中的虚函数实现,我会从编译器中获取错误消息。但是,如果我这样做,我还必须在派生类get_radius
中实现方法Square
,这没有任何意义,因为正方形没有半径。
有没有更好的方法来应对这个问题?感谢。
答案 0 :(得分:2)
如果你写
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
答案 1 :(得分:1)
一般情况下,如果没有强制转换,你就无法做到你想做的事情,因为运行时多态意味着:通过通用接口控制类层次结构。您的潜在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
实施的成员函数。
注意:一般来说,绝对需要演员表示设计不好,所以花一些时间考虑如何更好地设计代码会更好。
答案 2 :(得分:1)
您可以将非虚拟成员函数添加到派生类中,而无需在基类中定义它们,但是您无法从基类指针访问它们。 即:
//won't work
Shape* shapeP = new Circle();
shapeP ->get_radius();
//will work
Circle* circP = new Circle();
circP->get_radius();
你也可以为你知道你的形状是圆圈的情况投射你的形状指针,如vsoftco在他的回答中所提到的那样
答案 3 :(得分:1)
我有可能误解你,但听起来你正试图在circle->get_radius()
中拨打main
来测试它。问题是circle
实际上不是Circle*
对象,而是Shape*
。派生类的工作方式,您可以将它们分配给类型为它们扩展/实现的任何类或接口的变量 - 正如您在示例中所做的那样 - 因为派生类包含这些基类/接口的每个成员的定义。相反的情况并非如此;如你所说,get_radius()
对每个Shape
都没有意义。您收到错误的原因不是因为Circle
错误,而是因为您正试图获得恰好使用Shape*
函数实现的随机Circle
的半径。
换句话说,您(作为一个人)足够聪明,可以查看代码并看到circle
是Circle*
。编译器足够聪明,可以记住“在查找circle
的函数时,使用Circle
定义的函数”,但除此之外,它不知道该特定Shape*
实例与square
。据他所知,它可以对其中任何一个做的唯一事情是你告诉它每个 Shape
都能做到的事情。
在你不关心某个特定Shape
对象的情况下,这很方便 - 你需要的就是可以给你一个区域的东西。如果您需要知道半径,宽度和高度,或者Shape
有一个Circle *circle= new Circle(3);
circle->get_radius();
但其他属性没有的任何其他属性,则需要使用具有更具体类型的变量。
看看这对你有用吗</ p>
gem 'bcrypt', '3.1.11'