如何解析具有多个多态输入的方法调用
C++: How method calls with multiple polymorphic inputs are resolved?
假设我们有这些重载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
函数将被调用?
一般来说,当一个层次结构中有多个可以是任何类型的参数时,如何解析具有多个候选解析的方法调用?
(我希望我的问题+例子足够清楚,但如果有歧义,请让我知道)
注:还有这个电话呢?
Color* c = create_color(); //returns SolidColor instance
Shape* s = create_shape(); //returns Circle instance
paint(s,c);
将调用哪个版本的油漆?
给定您的代码,元素将在传递给函数时被复制,并切片:例如,在第一次重载中,如果传递Circle
给它,Shape s
将仅是Circle
信息的松散。如果Shape
是抽象的,这段代码甚至无法编译。
它的要点是,这段代码不会实现多态行为,因为它会为类似的代码在Java/c#。
第二点是重载解析发生在运行时多态性之前:也就是说,编译器在编译时通过选择最匹配的函数原型来选择调用哪个函数。
如果你有:
int main() {
Circle myCircle;
SolidColor mySolidColor;
paint(myCircle, mySolidColor);
}
编译器会报错,因为重载2和重载3都可以同样工作。
最重要的是,对于c++中的多态性,您希望通过引用来传递参数:
void paint(Shape& s, Color& c) {}
void paint(Circle& ci, Color& c) {}
void paint(Shape& s, SolidColor& sc) {}
如果有歧义让我知道
是一个歧义;它在电话里!
paint(Circle{}, SolidColor{});
此调用是二义性的,因为对于此调用,没有重载比其他重载足够专门化。Clang给出这个错误:
main.cpp:11:5: error: call to 'paint' is ambiguous
paint(Circle{}, SolidColor{});
一般来说,当一个层次结构中有多个可以是任何类型的参数时,如何解析具有多个候选解析的方法调用?
这被称为重载解析,这是一个太大的主题,无法在一个特定的SO答案中涵盖。关于该主题的cppreference文章应该为您提供一个合理的概述。
仍有一个未解决的挑战!
除了已经很好的答案,在你的方法中有两个问题值得提及:
-
要使用运行时多态性,您需要通过指针(如果可能的话智能指针)或引用传递参数。因为按值传递需要在编译时知道对象的大小。如果将子节点复制到父节点上,可能会导致切片。
-
只有虚成员函数是多态的。非虚成员函数和非成员函数是在编译时根据声明的对象类型选择的。
如何解决?
要在非成员疼痛函数中引入运行时多态性,可以考虑使用模板方法设计模式:
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();
}
这要求您的非成员函数可以仅在预定义的框架的基础上表示,并且多态性只能在某些阶段依赖于单个对象的多态成员函数
但是我可以做多态性同时依赖于几个类型吗?
是的,但是稍微复杂一点。最初的想法是使用多层多态性并结合重载来设计乒乓。这叫做双重调度。一般的思路是这样的:
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
}
- 当可输入框在窗口中处于活动状态时获得通知的任何方法
- 仅通过C++中数组初始化的不同方法,即可在同一输入上获得两个不同的答案
- C++ - 有什么方法可以将输入插入缓冲区/停止 cin.忽略需要输入?
- 有没有更好的方法可以让我接收这些输入?C++
- 将函数更改为具有设置函数输入变量的方法的类
- 输入可变大小矢量的正确方法
- 有没有一种方法可以接受数字数组而不接受垃圾值的输入
- isdigit() 和 isalnum() 给出错误,因为输入是一个常量字符并且无法转换。其他可能查看输入是否为数字的方法?
- 将用户输入绑定到UE4.22.3及更高版本中的UActorComponent方法
- 将整数输入数组的方法比 scanf() 或 cin 更快?
- QuickSort方法仅使用单个向量作为C 中的输入参数
- 检查字符串是否与可能的输入之一匹配的最有效方法是什么?
- 是否有一种方法可以避免标头文件中使用的constexpr函数输入全局范围,而无需额外的名称空间
- 从文件循环输入的更合适方法?
- 是否有任何方法可以在用户输入文本时读取字符
- 在 C++ 中解析 main 函数的大量输入的正确方法是什么
- 总结数字字符串输入的最佳方法
- C++简单的暴力项目密码输入方法
- C/C++ 中数字的快速输入方法
- 这是C++中最快的输入方法