Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C+中的双重分派+;_C++_Design Patterns_Dispatch - Fatal编程技术网

C++ C+中的双重分派+;

C++ C+中的双重分派+;,c++,design-patterns,dispatch,C++,Design Patterns,Dispatch,我需要以下类型的分派功能。在我的应用程序中,我真正拥有的是一个指向状态基类(foo)的指针以及一个指向度量基类(bar)的指针。根据传递给dispatch2函数的派生实例,我需要生成给定状态的估计度量。例如,派生的状态类可以是位置,派生的测量类可以是ToF(飞行时间)。然后,处理程序将从f(例如发射器位置)获取状态信息,以及从b(例如传感器位置)获取收集器信息,并计算给定的预期ToF。然后返回,并可与实际测量值(b)进行比较 string dispatch2(foo*f,bar*b){ if(d

我需要以下类型的分派功能。在我的应用程序中,我真正拥有的是一个指向状态基类(foo)的指针以及一个指向度量基类(bar)的指针。根据传递给dispatch2函数的派生实例,我需要生成给定状态的估计度量。例如,派生的状态类可以是位置,派生的测量类可以是ToF(飞行时间)。然后,处理程序将从f(例如发射器位置)获取状态信息,以及从b(例如传感器位置)获取收集器信息,并计算给定的预期ToF。然后返回,并可与实际测量值(b)进行比较

string dispatch2(foo*f,bar*b){
if(dynamic_cast(f))返回foo1(f,b);
否则if(dynamic_cast(f))返回foo2(f,b);
否则if(dynamic_cast(f))返回foo3(f,b);
抛出std::runtime_错误(“未定义f的调度”);
}
字符串foo1(foo*f,bar*b){
if(dynamic_cast(b))返回foo1bar1handler(f,b);
否则if(dynamic_cast(b))返回foo1bar2handler(f,b);
抛出std::runtime_错误(“foo1:未定义b的调度”);
}
字符串foo2(foo*f,bar*b){
if(dynamic_cast(b))返回foo2bar1handler(f,b);
否则if(dynamic_cast(b))返回foo2bar2handler(f,b);
抛出std::runtime_错误(“foo2:未定义b的调度”);
}
字符串foo3(foo*f,bar*b){
if(dynamic_cast(b))返回foo3bar1handler(f,b);
否则if(dynamic_cast(b))返回foo3bar2handler(f,b);
抛出std::runtime_错误(“foo3:未定义b的调度”);
}
字符串foo1bar1handler(foo*f,bar*b){返回“FooBar”;}
字符串foo2bar2handler(foo*f,bar*b){返回“FooBAR”;}
字符串foo3bar1handler(foo*f,bar*b){返回“FOoBar”;}
字符串foo2bar2handler(foo*f,bar*b){返回“FOoBAR”;}
字符串foo2bar1handler(foo*f,bar*b){返回“FOOBar”;}
字符串foo2bar2handler(foo*f,bar*b){返回“FOOBAR”;}
显然,对于我想显式处理的每个组合,都需要定义end方法,这是无法回避的。但是,我正在寻找其他方法来实现这一点。理想情况下,某些模式允许用户显式注册每个处理程序,任何未处理的组合都可能引发运行时异常。如有任何建议,将不胜感激。谢谢

一种方法(当然不是唯一的方法)是在foo上调用一个虚拟函数,并将其传递给bar。每个派生类型的foo都以相同的方式实现这个分派函数,它将自身传递给bar中的一个虚拟处理程序函数。 当需要添加更多时,可以扩展接口以接受新类型。所有foo函数都有相同的实现,但它们不同,因此“this”正确地表示对象的动态类型

Andrei Alexandrescu也对其在现代(C++)设计中的设计方案进行了很好的研究,它仍然涵盖了这个想法,但它是为C++ 98编写的,但它仍然值得阅读(尽管它所说的许多事情现在不能完成,部分是C++的一部分,部分是由于那本书)。 现场观看:

这个例子有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 Foo1\n"; }
void Bar1::accept(Foo2 * f) { std::cout << "Bar1 accepting Foo2\n"; }
void Bar1::accept(Foo3 * f) { std::cout << "Bar1 accepting Foo3\n"; }
void Bar2::accept(Foo1 * f) { std::cout << "Bar2 accepting Foo1\n"; }
void Bar2::accept(Foo2 * f) { std::cout << "Bar2 accepting Foo2\n"; }
void Bar2::accept(Foo3 * f) { std::cout << "Bar2 accepting Foo3\n"; }

//
// 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);
}

我使用了映射,其中键是pair,值是要调用的函数,其中未签名的值是调用typeinfo::hash()的结果。抛出异常或其他行为很容易,这只是当映射没有与哈希值对匹配的键时所做的事情。看看访问者模式。这非常有效。我修改了您的示例,以便在基类中提供一个默认的实现方法,以防派生类中没有处理所有排列,这样就可以了。非常感谢!
#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 Foo1\n"; }
void Bar1::accept(Foo2 * f) { std::cout << "Bar1 accepting Foo2\n"; }
void Bar1::accept(Foo3 * f) { std::cout << "Bar1 accepting Foo3\n"; }
void Bar2::accept(Foo1 * f) { std::cout << "Bar2 accepting Foo1\n"; }
void Bar2::accept(Foo2 * f) { std::cout << "Bar2 accepting Foo2\n"; }
void Bar2::accept(Foo3 * f) { std::cout << "Bar2 accepting Foo3\n"; }

//
// 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