Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.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+中的动态adhoc多态性+; 在我的C++代码中,我有一个类集合:代码> A1、A2、…、,所有这些都是从类 A派生的。我还有一个向量v包含指向所有类型a的对象的指针。我想实现一个函数foo(a*x,a*y),它在x和y类型中是动态的即席多态。为了使这更具体,设想A是Shape,A1,A2,…,是圆,Rect,…,和foo是相交(Shape*x,Shape*y)_C++_Design Patterns_Polymorphism_Overloading - Fatal编程技术网

C+中的动态adhoc多态性+; 在我的C++代码中,我有一个类集合:代码> A1、A2、…、,所有这些都是从类 A派生的。我还有一个向量v包含指向所有类型a的对象的指针。我想实现一个函数foo(a*x,a*y),它在x和y类型中是动态的即席多态。为了使这更具体,设想A是Shape,A1,A2,…,是圆,Rect,…,和foo是相交(Shape*x,Shape*y)

C+中的动态adhoc多态性+; 在我的C++代码中,我有一个类集合:代码> A1、A2、…、,所有这些都是从类 A派生的。我还有一个向量v包含指向所有类型a的对象的指针。我想实现一个函数foo(a*x,a*y),它在x和y类型中是动态的即席多态。为了使这更具体,设想A是Shape,A1,A2,…,是圆,Rect,…,和foo是相交(Shape*x,Shape*y),c++,design-patterns,polymorphism,overloading,C++,Design Patterns,Polymorphism,Overloading,对于我所关心的A的派生类型的组合,我可以使用类似于foo(A1*x,A2*y)的声明重载foo,但是这对向量v引用的对象不起作用,因为函数重载与虚拟方法不同,是静态处理的。我也不能使用形式为A1::foo(A2*y)的虚拟方法,因为这只动态解析方法类的类型(A1),而不是参数的类型(A2) 我想到的唯一解决方案是实现foo,如下所示: void foo(A *x, A*y) { if (A1* a1 = dynamic_cast<A1*>(x)) { if (A1* a1

对于我所关心的A的派生类型的组合,我可以使用类似于
foo(A1*x,A2*y)
的声明重载
foo
,但是这对向量
v
引用的对象不起作用,因为函数重载与虚拟方法不同,是静态处理的。我也不能使用形式为
A1::foo(A2*y)
的虚拟方法,因为这只动态解析方法类的类型(
A1
),而不是参数的类型(
A2

我想到的唯一解决方案是实现
foo
,如下所示:

void foo(A *x, A*y) {
  if (A1* a1 = dynamic_cast<A1*>(x)) {
    if (A1* a1 = dynamic_cast<A1*>(y)) {
      ...
    }
    ...
  }
  if (A2* a2 = dynamic_cast<A2*>(x)) {
    if (A1* a1 = dynamic_cast<A1*>(y)) {
      ...
    }  
    ...
  }
  ...
}
void foo(A*x,A*y){
如果(A1*A1=动态_-cast(x)){
如果(A1*A1=动态_铸造(y)){
...
}
...
}
如果(A2*A2=动态_投射(x)){
如果(A1*A1=动态_铸造(y)){
...
}  
...
}
...
}

然而,我总是被告知,诉诸动态强制转换很少是一个好主意。有没有更惯用的方法来实现这一点?

这是双重分派。访问者模式可以实现这一点。您需要一个虚拟函数,使第一个类型具体化以应用访问者。然后,您需要另一个虚拟函数使第二种类型具体化并返回访问者:

struct Shape
{
    // Each derived class simply calls visit with the concrete type:
    //     return visitor.visit(*this);
    virtual bool accept(const IntersectionVisitor& visitor) const = 0;

    // Each derived class return a visitor which knows how to calculate
    // the intersection of this particular class type with all types of
    // shapes. The visit() overrides of this visitor have access to both
    // concrete shape types.
    virtual IntersectionVisitor intersection_visitor() const = 0;
};

struct IntersectionVisitor
{
    // Calculate the intersection of this concrete shape with a Circle
    virtual bool visit(const Circle&) = 0;

    // Calculate the intersection of this concrete shape with a Rect
    virtual bool visit(const Rect&) = 0;
};

bool intersects(const Shape& shape1, const Shape& shape2)
{
    return shape2.accept(shape1.intersection_visitor());
}
仅仅因为你能,并不意味着你应该。您可以通过变体更简单地实现这一点:

using Shape = std::variant<Circle, Rect, ...>;

bool intersects(const Circle&, const Circle&) { ... }
bool intersects(const Circle&, const Rect&) { ... }
// all shape combinations, like before

// Visitation is just std::visit:
bool intersects(const Shape& shape1, const Shape& shape2)
{
    return std::visit([](const auto& s1, const auto& s2) {
            return intersects(s1, s2);
        }, shape1, shape2);
}
使用Shape=std::variant;
布尔相交(常数圆&,常数圆&){…}
布尔相交(常数圆&,常数矩形&){…}
//所有形状组合,像以前一样
//探视只是性病::探视:
布尔相交(常数形状和形状1、常数形状和形状2)
{
返回标准::访问([](常数自动&s1,常数自动&s2){
返回交点(s1、s2);
},形状1,形状2);
}

这是双重分派。访问者模式可以实现这一点。您需要一个虚拟函数,使第一个类型具体化以应用访问者。然后,您需要另一个虚拟函数使第二种类型具体化并返回访问者:

struct Shape
{
    // Each derived class simply calls visit with the concrete type:
    //     return visitor.visit(*this);
    virtual bool accept(const IntersectionVisitor& visitor) const = 0;

    // Each derived class return a visitor which knows how to calculate
    // the intersection of this particular class type with all types of
    // shapes. The visit() overrides of this visitor have access to both
    // concrete shape types.
    virtual IntersectionVisitor intersection_visitor() const = 0;
};

struct IntersectionVisitor
{
    // Calculate the intersection of this concrete shape with a Circle
    virtual bool visit(const Circle&) = 0;

    // Calculate the intersection of this concrete shape with a Rect
    virtual bool visit(const Rect&) = 0;
};

bool intersects(const Shape& shape1, const Shape& shape2)
{
    return shape2.accept(shape1.intersection_visitor());
}
仅仅因为你能,并不意味着你应该。您可以通过变体更简单地实现这一点:

using Shape = std::variant<Circle, Rect, ...>;

bool intersects(const Circle&, const Circle&) { ... }
bool intersects(const Circle&, const Rect&) { ... }
// all shape combinations, like before

// Visitation is just std::visit:
bool intersects(const Shape& shape1, const Shape& shape2)
{
    return std::visit([](const auto& s1, const auto& s2) {
            return intersects(s1, s2);
        }, shape1, shape2);
}
使用Shape=std::variant;
布尔相交(常数圆&,常数圆&){…}
布尔相交(常数圆&,常数矩形&){…}
//所有形状组合,像以前一样
//探视只是性病::探视:
布尔相交(常数形状和形状1、常数形状和形状2)
{
返回标准::访问([](常数自动&s1,常数自动&s2){
返回交点(s1、s2);
},形状1,形状2);
}

我同意别人告诉你的话。使用dynamic_cast是一种非常糟糕的代码味道。是的,它被称为“访问者模式”。一个好的C++教材将有一个完整的解释和例子。@ SavaVaveKik我知道访问者模式是什么,但是没有看到它如何应用于这个场景。你能详细说明一下吗?在两个相互作用的对象之间,这种类型的动态调度称为双重调度。它有一个关于如何在C++中使用访问者模式来完成它的例子。使用dynamic_cast是一种非常糟糕的代码味道。是的,它被称为“访问者模式”。一个好的C++教材将有一个完整的解释和例子。@ SavaVaveKik我知道访问者模式是什么,但是没有看到它如何应用于这个场景。你能详细说明一下吗?在两个相互作用的对象之间,这种类型的动态调度称为双重调度。它有一个例子,说明如何在C++中使用访问者模式来完成它。