我只是好奇。例如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
Rectangle
,area()
virtual
将始终被忽略?
答案 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;