【问题标题】:Code organizing代码组织
【发布时间】:2018-10-12 10:14:15
【问题描述】:

我有这个访问者模式实现:

class Visitor {
  public:
    Visitor() {}
    void visit(A *a){ a->doSomething(); }
    void visit(B *b){ b->doSomething(); }
};

class Base {
  public:
    Base() {}
    virtual void accept(Visitor *v) = 0;
};

class A: public Base {
  public:
    A():Base() {}
    void accept(Visitor *v) override { v->visit(this) };
    .....
};

class B: public Base {
  public:
    B():Base() {}
    void accept(Visitor *v) override { v->visit(this) };
};

问题在于 AB 在 Visitor 实现中的类型不完整。但我不想将实现放在单独的源文件中。

有没有办法把它放在一个单独的头文件中?

【问题讨论】:

  • "这是把它放在单个头文件中的一种方式吗?" 为什么要将实现放在头文件中?如果您将实现放入源文件 - 您不会遇到“不完整类型”的问题。
  • 尝试前向声明。
  • @AlexeyUsachov 仍然不允许在头文件中实现此类方法。 ab 的类型不完整的问题暗示了方法调用的问题,而不是 AB 的使用。据我所知,最终需要将 something 的实现移动到源文件中,并且没有纯标头实现的解决方案。

标签: c++ code-organization visitor-pattern


【解决方案1】:

转发声明AB。将您的 visit(A*a);visit(B*b); 移到访问者的类声明之外,并在 AB 类之后声明它。为了避免重复的符号,把它放到头文件中,例如 Header.h:

//forward declarations
class A;
class B;

class Visitor {
public:
    Visitor() {}
    void visit(A *a);
    void visit(B *b);
};

class Base {
public:
    Base() {}
    virtual void accept(Visitor *v) = 0;
};

class A: public Base {
public:
    A():Base() {}
    void accept(Visitor *v) override { v->visit(this); };
    void doSomething(){};
};

class B: public Base {
public:
    B():Base() {}
    void accept(Visitor *v) override { v->visit(this); };
    void doSomething(){};
};

这个声明应该放在cpp文件中,以避免重复符号,例如添加到main.cpp中:

#include "Header.h"

//outside declarations of methods
void Visitor::visit(A *a){ a->doSomething(); }
void Visitor::visit(B *b){ b->doSomething(); }

【讨论】:

  • 如果在多个源文件中包含这样的文件会怎样?一旦您尝试将其链接到最终应用程序,您不会收到链接器错误吗?
  • @AlgirdasPreidžius 是的,感谢您的评论,我已经对我的答案进行了改进,以避免链接器可能出现重复错误
【解决方案2】:

重点是:

只要你有两个类(例如 A 和 Visitor),并且每个类的实现都需要另一个类的声明,你就不能合并实现和声明。

在你的情况下:

class Visitor {
public:
    // Visitor's implementation needs A's declaration
    void visit(A *a){ a->doSomething(); }
};

class A {
  public:
    // A's implementation needs Visitor's declaration
    void accept(Visitor *v) { v->visit(this) };
    void doSomething() { ... };
};

这就是您希望在单独的文件中声明和实现的原因之一。 还有很多其他原因,包括不同的编译时间。

请问您为什么要在同一个文件中实现所有这些?

但是:

根据您要达到的目标,您可能想要欺骗它。但这将是一个痛苦的维护。 除非有非常好的和不寻常的原因,否则我永远不会这样做

例如,我认为这样的事情应该可以工作:

class Doer {
  public:
    // Doer's implementation don't needs Visitor's declaration
    virtual void doSomething()=0;
};

class A;
class Visitor {
public:
    // Visitor's implementation needs Doer's declaration
    void visit(A *a){ ((Doer*)a)->doSomething(); }
};

class A: public Doer {
  public:
    // A's implementation needs Visitor's declaration
    void accept(Visitor *v) { v->visit(this) };
    void doSomething() override { ... };
};

再一次,如果您有选择:不要这样做。更喜欢拆分文件。这种解决方法,即使有据可查,也很难维护。

【讨论】:

    猜你喜欢
    • 2011-08-08
    • 2011-06-04
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多