【问题标题】:C++ multimethods and compile time detectionC++ 多方法和编译时检测
【发布时间】:2014-08-29 07:22:28
【问题描述】:

我有以下代码:

class A{};
class B: public A{};
class C: public A{};

class MyVisitor
{
   public:
       void visit(B*);
       void visit(C*);
};

然后是A*对象的集合,我想实现如下:

1)

MyVisitor visitor;
for(vector<A*>::iterator it = vec.begin(); it!= vec.end();it++)
     visitor->visit(a);

2) 在编译时以某种方式确定,如果 A* 指向派生对象 D,并给出编译器错误,如果 MyVisitor::visit(D*) 函数不存在

我知道 1) 可以通过一些多方法实现来实现,我想我可以找到一些用于 c++ 的多方法实现。但是 2) 有可能吗?

【问题讨论】:

  • “多方法”我假设你的意思是多态演员?你有 Clojure 背景吗?
  • @SirDigbyChickenCaesar 多方法是与语言无关的概念(也称为多调度)
  • 无论如何,在实例化后的编译时,无法确定(至少在 c++ 的类型系统中)某个类的任意 INSTANCE 是派生类还是基类。
  • 它错过了Visitor_pattern 层次结构中的accept 部分
  • 也许您会对基于 Boost Variant(二进制访问)的技术感兴趣:stackoverflow.com/questions/18859699/…(我现在找不到其他可能更匹配的示例)

标签: c++ multimethod


【解决方案1】:

您可以像这样使用dynamic_cast(在for 循环的主体内),因为行为在运行时会有所不同(根据实际的数据类型)。

   ClassB* ba = dynamic_cast<ClassB*>(a);
   if (ba)
      visitor->visit(ba);
   ClassC* ca = dynamic_cast<ClassC*>(a);
   if (ca)
      visitor->visit(ca);

也许您的 visit 函数可能被声明为 virtual(对于您的 ClassD 事物)。

否则将您的类组织为类的树(而不是森林),并拥有最顶层的根类

  class Topmost {
     virtual int classnum() const;

并采用每个非抽象类赋予其独特的classnum 等的约定...或者具有元类机制(例如Qt 具有)

【讨论】:

  • 我想避免使用动态转换。
  • dynamic_cast 在运行时而不是在编译时运行。
  • 为什么要作废呢?这是使用它的一个很好的理由。
【解决方案2】:

你可以试试这样的。

#include <iostream>

class A
{
    virtual void visit() = 0;
};
class B: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }
};
class C: private A
{
public:
    void visit()
    {
        std::cout << __PRETTY_FUNCTION__ << "\n";
    }    
};

template <typename... Args>
class MyVisitor : public Args...
{
   public:
       template <typename T>
           void visit(T* t)
       {
           t->visit();
       }
};

int main()
{
    MyVisitor<B, C> visitor;
    B b;
    B* bp = &b;
    visitor.visit(bp);
    return 0;
}

Live example

【讨论】:

  • 为什么派生自Args...?您可以传递任何具有visit 方法的不相关类型,包括根本不是从A 派生的东西。
【解决方案3】:

您可以完全应用访问者模式:

class B;
class C;

class IVisitor
{
public:
    void visit(B&) = 0;
    void visit(C&) = 0;
};

class A
{
    virtual ~A() = default;
    virtual void accept(IVisitor& v) = 0;
};

class B: public A{ void accept(IVisitor& v) override { v.visit(*this); } };
class C: public A{ void accept(IVisitor& v) override { v.visit(*this); } };

【讨论】:

    猜你喜欢
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2023-04-09
    • 2018-11-13
    • 1970-01-01
    相关资源
    最近更新 更多