我正在使用Windows API在C++中创建自己的XUL实现。元素由XML解析器构造的事实要求它们具有相同的接口(interface),因此我们不需要为每个元素构造函数编写自定义代码。结果是我的大多数元素如下所示:

class Button : public Element
{
public:
    static const char * Type() { return "button"; }

private:
    friend class Element;
    Button(Element * inParent, const AttributesMapping & inAttributesMapping);
};


class Label : public Element
{
public:
    static const char * Type() { return "label"; }

private:
    friend class Element;
    Label(Element * inParent, const AttributesMapping & inAttributesMapping);
};


class Description : public Element
{
public:
    static const char * Type() { return "description"; }

    virtual bool init();

private:
    friend class Element;
    Description(Element * inParent, const AttributesMapping & inAttributesMapping);
};

因此,这里有很多代码重复。我想知道用这样的宏调用替换它们是否是一个好主意:
#define DECLARE_ELEMENT(ElementType, XULName)           \
class ElementType : public Element                      \
{                                                       \
public:                                                 \
    static const char * Type() { return XULName; }      \
                                                        \
private:                                                \
    friend class Element;                               \
    ElementType(                                        \
        Element * inParent,                             \
        const AttributesMapping & inAttributesMapping); \
};                                                      \


DECLARE_ELEMENT(Window, "window")
DECLARE_ELEMENT(Button, "button")
DECLARE_ELEMENT(Label, "label")

我还没有完全弄清楚这个概念,因此这里缺少一些东西,例如类定义,以及(也许)可以为每个元素添加方法的能力。

但我想知道您在这种情况下使用宏的意见。随时分享您的想法。

编辑

我现在正在使用一个小的ruby脚本,该脚本从一组模板生成源文件和头文件。我对脚本进行了增强,以便文件也自动标记为要在SVN上添加,并且将Visual Studio项目文件修改为包括这些文件。这节省了我很多的体力劳动。我对这种解决方案感到非常满意。仅供引用,这是模板现在的样子:
#ifndef {{ELEMENT_NAME_UPPER}}_H_INCLUDED
#define {{ELEMENT_NAME_UPPER}}_H_INCLUDED


#include "XULWin/Element.h"


namespace XULWin
{

    class {{ELEMENT_NAME}} : public Element
    {
    public:
        static ElementPtr Create(Element * inParent, const AttributesMapping & inAttr)
        { return Element::Create<{{ELEMENT_NAME}}>(inParent, inAttr); }

        static const char * Type() { return "{{ELEMENT_TYPE}}"; }

        virtual bool init();

    private:
        friend class Element;
        {{ELEMENT_NAME}}(Element * inParent, const AttributesMapping & inAttributesMapping);
    };

} // namespace XULWin


#endif // {{ELEMENT_NAME_UPPER}}_H_INCLUDED

CPP文件:
#include "XULWin/{{ELEMENT_NAME}}.h"
#include "XULWin/{{ELEMENT_NAME}}Impl.h"
#include "XULWin/AttributeController.h"
#include "XULWin/Decorator.h"


namespace XULWin
{

    {{ELEMENT_NAME}}::{{ELEMENT_NAME}}(Element * inParent, const AttributesMapping & inAttributesMapping) :
        Element({{ELEMENT_NAME}}::Type(),
                inParent,
                new {{ELEMENT_NAME}}Impl(inParent->impl(), inAttributesMapping))
    {
    }


    bool {{ELEMENT_NAME}}::init()
    {
        return Element::init();
    }

} // namespace XULWin

最佳答案

我不会在这里使用宏。线索在您的“描述”类中,该类具有一个额外的成员函数init,其他成员没有。因此,您将无法使用宏来定义它,而是您可以手动扩展该宏并添加多余的行。

对我来说,这比仅写出所有类定义更大地违反了DRY。几乎不重复自己,而只重复一种情况,通常很难维持一致地重复自己。 DRY的目的是找到良好的抽象,而不仅仅是减少样板。

不过,我可以用SetAttributes类中的Element函数替换这些构造函数。这可能会减少每个派生类中实际需要的样板数量,因为构造函数是不能从基础继承的一件事。但这取决于每个类的构造函数的实现有多相似。

关于c++ - D.R.Y和 “avoid macros”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1554910/

10-09 03:08