C++双重调度
Double Dispatch in C++
我需要以下类型的调度功能。 在我的应用程序中,我真正拥有的是指向状态基类 (foo( 的指针以及指向度量基类 (bar( 的指针。 根据传递给 dispatch2 函数的派生实例,我需要在给定状态的情况下生成估计的度量值。 例如,派生状态类可以是位置,派生的测量类可以是ToF(飞行时间(。 然后,处理程序将从f(例如发射器位置(获取状态信息,并从b(例如传感器位置(获取收集器信息,并计算给定的预期ToF。 然后返回该值,并可以与实际测量值(b(进行比较。
string dispatch2(foo* f, bar* b) {
if ( dynamic_cast<Foo>(f) ) return foo1(f,b);
else if ( dynamic_cast<FOo>(f) ) return foo2(f,b);
else if ( dynamic_cast<FOO>(f) ) return foo3(f,b);
throw std::runtime_error("dispatch for f not defined");
}
string foo1(foo* f, bar* b) {
if ( dynamic_cast<Bar>(b) ) return foo1bar1handler(f,b);
else if ( dynamic_cast<BAR>(b) ) return foo1bar2handler(f,b);
throw std::runtime_error("foo1: dispatch for b not defined");
}
string foo2(foo* f, bar* b) {
if ( dynamic_cast<Bar>(b) ) return foo2bar1handler(f,b);
else if ( dynamic_cast<BAR>(b) ) return foo2bar2handler(f,b);
throw std::runtime_error("foo2: dispatch for b not defined");
}
string foo3(foo* f, bar* b) {
if ( dynamic_cast<Bar>(b) ) return foo3bar1handler(f,b);
else if ( dynamic_cast<BAR>(b) ) return foo3bar2handler(f,b);
throw std::runtime_error("foo3: dispatch for b not defined");
}
string foo1bar1handler(foo* f, bar* b) {return "FooBar";}
string foo2bar2handler(foo* f, bar* b) {return "FooBAR";}
string foo3bar1handler(foo* f, bar* b) {return "FOoBar";}
string foo2bar2handler(foo* f, bar* b) {return "FOoBAR";}
string foo2bar1handler(foo* f, bar* b) {return "FOOBar";}
string foo2bar2handler(foo* f, bar* b) {return "FOOBAR";}
显然,没有办法解决为我想显式处理的每个组合定义结束方法的需求。 但是,我正在寻找实现这一点的替代方法。 理想情况下,某些允许用户显式注册每个处理程序的模式,以及未处理的任何组合都可能引发运行时异常。 任何建议将不胜感激。 谢谢
一种方法(当然不是唯一的方法(是在 foo 上调用一个虚函数,传递它吧。 每个派生类型的 foo 都以相同的方式实现此调度函数,它将自身传递给 bar 中的虚拟处理程序函数。 当您需要添加更多接口时,您可以扩展接口以接受新类型。 所有 foo 函数都有相同的实现,但它们有所不同,因此"this"是正确的对象的动态类型。
此外,Andrei Alexandrescu在他的(现在不那么现代的(书《现代C++设计》中对此进行了很好的研究,该书仍然涵盖了这个想法,但为c ++ 98编写,但绝对仍然值得一读(尽管它说许多不能做的事情现在是C++的一部分,部分原因是这本书。
现场观看:https://godbolt.org/z/oRyVJx
此示例有 3 个 Foo 类和 2 个 Bar 类。
#include <iostream>
class BarBase;
class FooBase {
public:
virtual ~FooBase() = default;
virtual void dispatch(BarBase*) = 0;
};
class Foo1;
class Foo2;
class Foo3;
class BarBase {
public:
virtual ~BarBase() = default;
virtual void accept(Foo1*) = 0;
virtual void accept(Foo2*) = 0;
virtual void accept(Foo3*) = 0;
};
class Bar1 : public BarBase {
public:
void accept(Foo1*) override;
void accept(Foo2*) override;
void accept(Foo3*) override;
};
class Bar2 : public BarBase {
public:
void accept(Foo1*) override;
void accept(Foo2*) override;
void accept(Foo3*) override;
};
class Foo1 : public FooBase {
public:
void dispatch(BarBase* bar) override { bar->accept(this); }
};
class Foo2 : public FooBase {
public:
void dispatch(BarBase* bar) override { bar->accept(this); }
};
class Foo3 : public FooBase {
public:
void dispatch(BarBase* bar) override { bar->accept(this); }
};
void Bar1::accept(Foo1 * f) { std::cout << "Bar1 accepting Foo1n"; }
void Bar1::accept(Foo2 * f) { std::cout << "Bar1 accepting Foo2n"; }
void Bar1::accept(Foo3 * f) { std::cout << "Bar1 accepting Foo3n"; }
void Bar2::accept(Foo1 * f) { std::cout << "Bar2 accepting Foo1n"; }
void Bar2::accept(Foo2 * f) { std::cout << "Bar2 accepting Foo2n"; }
void Bar2::accept(Foo3 * f) { std::cout << "Bar2 accepting Foo3n"; }
//
// Doesn't know which types of foo and bar it has, but it doesn't matter...
//
void call(FooBase& foo, BarBase& bar) {
foo.dispatch(&bar);
}
int main() {
Foo1 f1;
Foo2 f2;
Foo3 f3;
Bar1 b1;
Bar2 b2;
call(f1, b1);
call(f2, b1);
call(f3, b1);
call(f1, b2);
call(f2, b2);
call(f3, b2);
}
输出:
Bar1 accepting Foo1
Bar1 accepting Foo2
Bar1 accepting Foo3
Bar2 accepting Foo1
Bar2 accepting Foo2
Bar2 accepting Foo3
相关文章:
- 如何在c++中实现处理器调度模拟器
- 如何在 C++17 STL 并行算法中处理调度?
- 无法使用迭代器标记调度实例化模板
- 在 c++11 中为 pthread 设置调度参数
- 如何在 assert() 和 static_assert() 之间调度,如果在 constexpr 上下文中依赖?
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- C++双重调度
- 动态调度到模板函数C++
- 正确调度消息 UART
- 在 C++ 中使用枚举而不是结构进行标记调度
- 如何实现从 Windows 脚本主机到脚本的事件调度
- C++内置类型的基于类型的调度
- 用于GPU上的瓦片度量和调度的Halide
- SFINAE和标签调度之间的差异
- C++ 如何按标签调度到不同的模板函数
- 在 boost::asio 中发布和调度有什么区别?
- 5 CPU的任务调度N进程
- 究竟发生了什么,我们需要在 c++ 中双重调度/访客
- openMp 动态调度与按处理时间排序任务时的 LPT 调度相同吗?
- C++中的双重调度不起作用