我有大约50个小的,非常相似的结构化类的集合 所有这些都来自共同的基础。这些类表示读入的项目 从一个文件作为字符串对,其中第一个字符串用于标识 对的类型(应该使用派生类来表示数据)和 第二个是数据本身。还有一个访客(如访客模式) 与派生类关联的类和用于生成的工厂类 来自类型标识字符串的适当派生类。
设置看起来像这样:
class NodeItemVisitor; // Forward declaration.
class NodeItemBase
{
public:
std::string get_val() const { return val; }
virtual std::string idstr() const = 0;
virtual void accept(NodeItemVisitor& v) = 0;
private:
std::string val;
};
// Forward declarations of derived classes.
class NodeItemA;
class NodeItemB;
...
class NodeItemZ;
class NodeItemVisitor
{
public:
virtual void visit(NodeItemA& ni) = 0;
...
virtual void visit(NodeItemZ& ni) = 0;
};
class NodeItemA : public NodeItemBase
{
public:
virtual std::string idstr() const { return "A"; }
virtual void accept(NodeItemVisitor& v) { v.visit(*this); return; }
};
...
class NodeItemZ : public NodeItemBase
{
public:
virtual std::string idstr() const { return "Z"; }
virtual void accept(NodeItemVisitor& v) { v.visit(*this); return; }
};
class NodeItemFactory
{
public:
// Uses a lookup table to map the input string to one of the "mkni"
// functions below and then calls it.
static NodeItemBase* mknifromid(const std::string& id);
private:
static NodeItemBase* mkniA(void) { return new NodeItemA(); }
...
static NodeItemBase* mkniZ(void) { return new NodeItemZ(); }
};
由于此代码非常重复,占用了大量空间,并且因为添加了一个 新项目类型需要记住在几个地方添加行,我是 使用宏来创建派生类并添加:
#define ADD_NODE_ITEMS \
ADD_NODE_ITEM(A); \
...
ADD_NODE_ITEM(Z);
#define ADD_NODE_ITEM(ID) \
class NodeItem##ID : public NodeItemBase \
{ \
public: \
virtual std::string idstr() const { return #ID; } \
virtual void accept(NodeItemVisitor& v) { v.visit(*this); return; } \
}
ADD_NODE_ITEMS
#undef ADD_NODE_ITEM
class NodeItemVisitor
{
public:
#define ADD_NODE_ITEM(ID) \
virtual void visit(NodeItem##ID& ni) = 0;
ADD_NODE_ITEMS
#undef ADD_NODE_ITEM
};
class NodeItemFactory
{
public:
// Uses a lookup table to map the input string to one of the "mkni"
// functions below and then calls it.
static NodeItemBase* mknifromid(const std::string& id);
private:
#define ADD_NODE_ITEM(ID) \
static NodeItemBase* mkni##ID(void) { return new NodeItem##ID(); }
ADD_NODE_ITEMS
#undef ADD_NODE_ITEM
};
#undef ADD_NODE_ITEMS
现在提出的问题是:使用宏来实现" compact"这段代码"对"办法 要做到这一点,还是有更优雅/更清洁的方法?评论暗示 我们也欢迎另一种设计:我还很新 面向对象的编程,并没有对什么"对"有良好的感觉。爱好。
非常感谢你!
答案 0 :(得分:2)
您可能需要查看Andrei Alexandrescu的“Modern C ++ Design”副本,其中显示了如何使用C ++模板系统自动生成大部分代码。 Alexandrescu将两个章节专门用于访问者模式并自动生成类层次结构,这看起来与您正在寻找的完全相同。我不会尝试在这个答案中复制代码,主要是因为它非常密集,我可能会弄错,而且这本书有更好的解释。 : - )
答案 1 :(得分:1)
也许所有继承都有一个原因,但它确实看起来像很多代码。
template<typename T>
struct class_trait;
#define QUOTE(X) #X
#define CLASS_TRAIT(NAME) \
template<> struct class_trait<NAME> { \
static std::string class_string() {return QUOTE(NAME);} \
}
template<typename T>
std::string GetClassString() {
return class_trait<T>::class_string();
}
通常,我不希望需要该类型的内部来创建访问者。我怀疑你使用它是违反开放/封闭的委托人。我建议熟悉boost :: variant和boost :: static_visitor,看看他们是如何做到的。也许我有点放肆,不确定。
答案 2 :(得分:0)
我会推出一个小型生成器脚本,而不是手动触摸生成的源代码。拥有显式代码(无宏)总是更适合调试。
答案 3 :(得分:0)
我会努力使用代码生成器/模板语言。我已经专业地完成了Nvelocity模板引擎的组合,它是非常简单和良好的语言(但是不是很好的解析器!)和C#,效果非常好。
我不知道您是否使用Visual Studio 2010,但我听说它现在有一个名为T4的模板引擎。我从来没有尝试过,所以我不是理想的人,但如果我在你的位置,我会按照这个方向进行调查。