是否可以在不使用虚拟关键字的情况下调用(同名)子函数?

时间:2017-02-13 11:11:54

标签: c++ polymorphism

我只是好奇。例如Here

#include <iostream>

class Polygon {
  protected:
    int width, height;

  public:
    Polygon (int a, int b) : width(a), height(b) {}

    int area() { return 0; };
};

class Rectangle: public Polygon {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}

    int area() { return width*height; }
};

int main () {
  Polygon * ppoly1 = new Rectangle (4,5);
  std::cout << ppoly1->area() << std::endl;
  delete ppoly1;
}   

我可以在area()上设置虚拟Rectangle而不调用对象area()的{​​{1}}功能吗?或者它是不可能的,如果没有父母Polygon Rectanglearea() virtual将始终被忽略?

3 个答案:

答案 0 :(得分:6)

如果函数不是虚函数,则编译器根据指针的类型(而不是对象的实际类型)决定调用哪个函数,因此可以使用强制转换:

std::cout << static_cast<Rectangle*>(ppoly1)->area() << std::endl;

警告:在这种情况下,静态强制转换是正常的,因为您肯定知道强制转换会成功。通常情况并非如此,如果转换不成功,您可能会得到未定义的行为。

另请注意,您在此处显示的代码(我假设这只是一个简化示例)是声明虚拟方法的典型示例。只有当你有充分的理由不这样做时,你才会寻找不同的解决方案(例如,看看@axalis的答案)。

答案 1 :(得分:2)

一种可能性是编译时多态(CRTP):

template<class IMPL_T>
class Polygon {
  protected:
    int width, height;

  public:
    Polygon (int a, int b) : width(a), height(b) {}

    int area() { return static_cast<IMPL_T *>(this)->area(); };
};

class Rectangle: public Polygon<Rectangle> {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}

    int area() { return width*height; }
};

但是请注意,那么你不能拥有一个基类指针(因为每个对象的基础是不同的类型)。再次使用模板化调用。

如果您确实需要运行时多态性(即指向基类的指针),虚拟调用通常是最佳解决方案,您不可能自己推出更好的东西(对于例如,通过类型getter和静态强制类型的开关替换不仅更加丑陋,而且在许多情况下性能也更差,而dynamic_cast比调用虚拟方法要慢得多。

答案 2 :(得分:0)

  

我可以调用对象Rectangle的area()函数而不在Polygon上设置虚拟区域()吗?

是的,如果您确定指针实际上指向static_cast,您可Polygon* Rectange*Rectangle

Polygon * ppoly1 = new Rectangle (4,5);
auto asRectangle = static_cast<Rectangle*>(ppoly1);
std::cout << asRectangle->area() << std::endl;