派生类中不同方法的多态性

时间:2017-05-13 18:48:55

标签: c++ class oop polymorphism

在尝试学习多态时,我对一件事感到困惑。请考虑以下情况:

存在基类Shape以及派生类CircleSquare。使用多态,我可以将方法get_area实现为基类中的虚函数,并在派生类CircleSquare中实现此功能的各个版本。

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,这没有任何意义,因为正方形没有半径。

有没有更好的方法来应对这个问题?感谢。

4 个答案:

答案 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的半径。

换句话说,您(作为一个人)足够聪明,可以查看代码并看到circleCircle*。编译器足够聪明,可以记住“在查找circle的函数时,使用Circle定义的函数”,但除此之外,它不知道该特定Shape*实例与square。据他所知,它可以对其中任何一个做的唯一事情是你告诉它每个 Shape都能做到的事情。

在你不关心某个特定Shape对象的情况下,这很方便 - 你需要的就是可以给你一个区域的东西。如果您需要知道半径,宽度和高度,或者Shape有一个Circle *circle= new Circle(3); circle->get_radius(); 但其他属性没有的任何其他属性,则需要使用具有更具体类型的变量。

看看这对你有用吗<​​/ p>

gem 'bcrypt', '3.1.11'