假设我们有这些重载的C ++函数:
void paint(Shape s, Color c) {}
void paint(Circle ci, Color c) {}
void paint(Shape s, SolidColor sc) {}
显然,Shape
是Circle
的父级,而Color
是SolidColor
的父级。
如果我进行如下函数调用:paint(myCircle, mySolidColor)
将调用哪个版本的paint
函数?
通常,当多个参数可以是层次结构中的任何类型时,如何解析多个分辨率候选的方法调用?
(我希望我的问题+例子很清楚,但如果有歧义让我知道)
P.S。这个电话怎么样?
Color* c = create_color(); //returns SolidColor instance
Shape* s = create_shape(); //returns Circle instance
paint(s,c);
将调用哪个版本的油漆?
答案 0 :(得分:6)
给定您的代码,元素将在传递给函数时被复制并切片:例如,在第一次重载时,Shape s
只会传递Circle
信息,如果您传递{ {1}}。
如果Circle
是抽象的,则此代码甚至不会编译。
它的要点是,这段代码不会像Java / C#中的类似代码那样实现多态行为。
第二点是重载解析在运行时多态之前发生:也就是说,编译器在编译时选择调用函数,通过选择最匹配的函数原型。
如果你有:
Shape
然后编译器将complain due to ambiguity,因为重载2和3都可以同样工作。
最重要的是,对于C ++中的多态性,您希望通过引用传递参数:
int main() {
Circle myCircle;
SolidColor mySolidColor;
paint(myCircle, mySolidColor);
}
答案 1 :(得分:5)
如果有歧义让我知道
是歧义;它正在通话中!
paint(Circle{}, SolidColor{});
此调用不明确,因为此调用没有过载比其他过载更专业。 Clang给出了这个错误:
main.cpp:11:5: error: call to 'paint' is ambiguous
paint(Circle{}, SolidColor{});
通常,当多个参数可以是层次结构中的任何类型时,如何解析多个分辨率候选的方法调用?
这称为重载决策,在特定的SO答案中涉及的主题太多了。关于该主题的cppreference文章应该为您提供合理的概述。
答案 2 :(得分:1)
仍有未解决的挑战!
除了已经很好的答案之外,值得一提的是你的方法中的两个问题:
要使用运行时多态性,您需要通过指针(如果可能的智能指针)或通过引用传递参数。因为按值传递需要在编译时知道对象的大小。如果将子项复制到父项上,可能会导致切片。
只有虚拟成员函数是多态的。非虚拟成员函数和非成员函数在编译时根据声明的对象类型选择。
如何解决?使用模板方法?
要在非成员疼痛函数中引入运行时多态性,您可以考虑使用template method design pattern:
class Shape {
public:
virtual void paint_shape() = 0 ;
virtual ~Shape() {} // polymorphic class => better have destructor being virtual
};
class Color {
public:
virtual void set_color() = 0;
virtual void reset_color() = 0;
virtual ~Color() {}
};
...
void paint(Shape *s, Color *c) {
activate_window ();
c->set_color(); // use polymorphic function
s->paint_shape();
c->set_color(); // use polymorphic function
refresh_window();
}
这要求您的非成员函数可以仅基于预定义的骨架表示,并且只能在某些阶段依赖于单个对象的多态成员函数才能实现该多态性
但我可以同时依赖几种类型的多态性吗?
是的,但它稍微复杂一些。最初的想法是使用多级多态性设计乒乓,并结合重载。它被称为double dispatch。一般的想法是这样的:
class Color;
class Shape {
public:
virtual void paint_color(Color *c) = 0 ;
virtual ~Shape() {}
};
class Circle : public Shape {
public:
void paint_color(Color *c) override;
};
class Color {
public:
virtual void paint_shape (Circle*) = 0;
virtual void paint_shape (Square*) = 0;
...
virtual ~Color() {}
};
class SolidColor : public Color {
public:
void paint_shape (Circle*) override ;
void paint_shape (Square*) override ;
};
void Circle::paint_color(Color *c) {
c->paint_shape (this); // this is Circle* => bounce on polymorphic color
} // with real determined shape
void SolidColor::paint_shape(Circle *c) {
paint_shape_and_color (c, this); // this is SolidColor* => bounce on overload with
} // determined shape and color
void paint(Shape *s, Color *c) {
s->paint_shape(c); // polymorphic call
}
void paint_shape_and_color (Circle *s, SolidColor *c) {
... // real painting
}