2

我必须将一堆成员添加到一个类中。我想添加一个宏,例如:

#define MEMBER(TYPE,NAME) \
    private: TYPE m_##NAME; \
    public: TYPE get##NAME() const { return m_##NAME; } \
    public: void set##NAME(TYPE in##NAME) { m_##NAME = in##NAME; }

然后使用它将成员添加到类中:

class foo {
    MEMBER(std::string, OutputDir);
    MEMBER(int, MaxIterations);
    MEMBER(double, OptimizationCutoff);
    // And a couple dozen more members...
    public:
    // The rest of the class declarations
};

显然,这样做的目的是简化多个这样的代码实例,每个类成员 3 行:

private: std::string m_OutputDir;
public: std::string getOutputDir() const { return m_OutputDir; }
public: void setOutputDir(std::string inOutputDir) { m_OutputDir = inOutputDir; }

有没有考虑反对这样的编码?

4

1 回答 1

4

首先,我要指出一个观察结果。您在这里定义的宏似乎完全没用。我得到了你想要做的——用一行代码声明一个成员变量和简单的 getter 和 setter 方法。

我会反驳:如果您只是用简单的 getter 和 setter 公开这些成员变量,为什么不直接创建成员变量public并完成它呢?

有没有考虑反对这样的编码?

是的,所有关于邪恶滥用宏的常见问题。让我们来看看它们与这里有关的一些内容。

你正在创造一种只有你会知道的秘密语言。

如下所示的代码:

class foo {
    MEMBER(std::string, OutputDir);
    MEMBER(int, MaxIterations);
    MEMBER(double, OptimizationCutoff);
    // And a couple dozen more members...
    public:
    // The rest of the class declarations
};

乍一看,它的构造可能有些foo明显,但是在维护或扩展其中一个成员或宏本身时,有许多细节被掩盖了。

例如,只看一眼,我就知道您正在声明一个 member OutputDir,但实际上没有任何迹象表明它是数据成员还是成员函数。如果是成员函数,返回类型是什么?参数是什么?我将如何声明成员函数模板?模板参数是什么?

您在这里构建了一个语法,在第一次键入代码时可能会节省一两次击键,但当有人需要回答这些问题中的任何一个时,可能会产生数小时的挫败感和头疼。由于除了您之外没有任何人记录或支持它,因此您的宏最终类似于只有您知道的秘密语言。

宏很难调试

在调试使用宏的代码时,您会看到替换的文本——而不是宏或它的调用方式。这可能非常令人困惑。

宏没有命名空间

宏是一种暴力文本替换工具。它们不尊重任何名称空间或范围,并且在定义和调用它们的任何地方都普遍适用。这完全绕过 C++ 类型系统,让您编写否则会引发错误的代码。

宏有奇怪的和意想不到的副作用,并且被应用在你没有预料到的地方。

一个常见的例子是 VisualStudio 对minandmax宏的定义,它破坏了标准库中同名的函数。副作用可能很奇怪,而且如前所述,很难调试。

于 2013-10-18T19:26:55.267 回答