如何简化C ++中的接口声明?

时间:2010-07-31 23:58:44

标签: c++ interface declaration

我的界面声明通常(总是?)遵循相同的方案。这是一个例子:

class Output
{
public:
    virtual ~Output() { }

    virtual void write( const std::vector<char> &data ) = 0;

protected:
    Output() { }

private:
    Output( const Output &rhs ); // intentionally not implemented
    void operator=( const Output &other );  // intentionally not implemented
};

样板始终是相同的:公共虚拟析构函数,构成实际接口的一些纯虚方法。受保护的默认ctor,禁用的复制构造和复制分配。我开始使用两个小助手宏,可以用来简化上面的

ABSTRACT_BASECLASS_BEGIN(Output)
    virtual void write( const std::vector<char> &data ) = 0;
ABSTRACT_BASECLASS_END(Output)

不幸的是,我没有找到一个很好的方法只使用一个宏来做到这一点。更好的是,我想完全避免使用宏。然而,我想到的唯一一件事是代码生成器,这对我来说有点矫枉过正。

在C ++中声明接口的最简单方法是什么 - 直接在语言中。预处理器的使用是可以接受的,但我想避免使用外部代码生成器。

4 个答案:

答案 0 :(得分:3)

考虑使用基类:

class NoncopyableBase
{
public:
    NoncopyableBase() { }
    virtual ~NoncopyableBase() { }
private:
    NoncopyableBase(const NoncopyableBase&);
    void operator=(const NoncopyableBase&);
};

从此基类派生的任何类都是不可复制的,并且将具有虚拟析构函数。

答案 1 :(得分:3)

就个人而言,我会删除复制构造函数声明。您有纯虚函数,因此无论如何都无法通过切片创建此类的实例。如果派生类由于其拥有的资源的性质而不可复制;它可以标记为不可复制。

然后我将摆脱受保护的默认构造函数;它没有做任何事情,你必须从这个类派生,因为你有纯虚函数,所以它不会阻止任何使用。

虽然标记副本赋值运算符可以防止某人执行*pBase1 = *pBase2(实际上是无操作),但我个人并不相信尝试阻止它是值得的。由于您的类没有数据成员,因此编译器生成的没有固有的危险,因此用户可以正确使用指针或对基类的引用。

我会选择:

class Output
{
public:
    virtual ~Output() {}
    virtual void write( const std::vector<char> &data ) = 0;
};

答案 2 :(得分:3)

  

不幸的是,我没有找到一个很好的方法只用一个宏来做到这一点。

IMO,最简单的解决方案是将默认方法放入宏。像这样:

#include <vector>

#define DEFAULT_CLASS_METHODS(C) public: \
        virtual ~C(){}; \
    protected: \
        C(){}; \
    private: \
        inline C(const C& rhs){}; \
        inline void operator=(const C& other){}; 

class Output{
    DEFAULT_CLASS_METHODS(Output)
public:
    virtual void write(const std::vector<char> &data) = 0;
};

这样,* .h文件中每个类定义只需要一个宏。您将需要额外的宏来实际声明一些* .cpp文件中的复制构造函数和赋值运算符,或者您可以使内联的默认复制构造函数和赋值运算符,这将把所有内容都包装到单个宏中。

唯一的问题是你需要输入两次类名。

如果不输入两次类名,有一种不那么优雅的方法:

#include <vector>

#define BEGIN_INTERFACE(C) class C{ \
    public: \
        virtual ~C(){}; \
    protected: \
        C(){}; \
    private: \
        inline C(const C& rhs){}; \
        inline void operator=(const C& other){}; 

BEGIN_INTERFACE(Output)
public:
    virtual void write(const std::vector<char> &data) = 0;
};

正如您所看到的,在这种情况下,宏会打开{括号,这会产生误导。

答案 3 :(得分:2)

这类事情怎么样:

ABSTRACT_BASECLASS(Output,
    (virtual void write( const std::vector<char> &data ) = 0;)
    (more methods))

(first)(second)(...)是一个提升预处理器序列,就宏而言,它实际上是单个参数:http://www.boost.org/doc/libs/1_43_0/libs/preprocessor/doc/index.html

#define BASECLASS(name, methods) \
...\
BOOST_PP_SEQ_CAT(methods)\  //will concatenate methods declarations
...\