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

发布于 2024-09-12 04:00:27 字数 767 浏览 8 评论 0原文

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

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
};

样板总是相同的:公共虚拟析构函数,一些构成实际接口的纯虚拟方法。受保护的默认构造函数,禁用副本构造和副本分配。我开始使用两个小辅助宏,它们可用于简化上面的操作

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

,不幸的是,我没有找到仅用一个宏来完成此操作的好方法。更好的是,我想完全避免使用宏。然而,我唯一想到的是代码生成器,这对我来说有点大材小用。

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

My interface declarations usually (always?) follow the same scheme. Here's an example:

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
};

The boilerplate is always the same: public virtual destructor, a few pure virtual methods which make up the actual interface. protected default ctor, disabled copy construction and copy assignment. I started using two little helper macros which can be used to simplify the above to

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

Unfortunately, I didn't find a nice way to do this with just a single macro. Even better, I'd like to avoid macros entirely. However, the only thing which came to my mind was a code generator, which is a bit overkill for me.

What is the simplest way to declare an interface in C++ - directly in the language. Preprocessor use is acceptable, but I'd like to avoid external code generators.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我乃一代侩神 2024-09-19 04:00:27

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

然后我会摆脱受保护的默认构造函数;它不执行任何操作,并且在任何情况下都必须从此类派生,因为您具有纯虚函数,因此它不会阻止任何使用。

尽管标记复制赋值运算符可以防止有人执行 *pBase1 = *pBase2 (实际上是无操作),但我个人并不认为值得费心去阻止它。由于您的类没有数据成员,因此编译器生成的类没有固有的危险,因此实际上取决于用户是否适当地使用对基类的指针或引用。

我会选择:

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

Personally, I would remove the copy constructor declaration. You have pure virtual functions so instances of this class can't be created by slicing in any case. If a derived class isn't copyable because of the nature of a resource that it holds; it can mark itself as non-copyable.

Then I would get rid of the protected default constructor; it doesn't do anything and you have to derive from this class in any case as you have pure virtual functions so it's not preventing any usage.

Although marking the copy assignment operator prevents someone doing *pBase1 = *pBase2 (effectively a no-op), personally I'm not convinced that it's worth the bother of trying to prevent it. As your class has no data members there's no inherent danger in the compiler generated one, it's really up to user to use pointers or references to base classes appropriately.

I would just go with:

class Output
{
public:
    virtual ~Output() {}
    virtual void write( const std::vector<char> &data ) = 0;
};
瞎闹 2024-09-19 04:00:27

考虑使用基类:

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

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

Consider using a base class:

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

Any class derived from this base class will be noncopyable and will have a virtual destructor.

若沐 2024-09-19 04:00:27

不幸的是,我没有找到仅用一个宏来完成此操作的好方法。

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;
};

如您所见,在这种情况下,宏会吃掉左括号,这将非常具有误导性。

unfortunately, I didn't find a nice way to do this with just a single macro.

IMO, the easiest solution is to put default methods into macro. Like this:

#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;
};

This way you'll need only one macro per class definition in *.h file. You will need additional macro to actually declare copy constructor and assignment operator in some *.cpp file or you could make default copy constructor and assignment operators inline, which will wrap everything into single macro.

The only problem is that you'll need to type class name twice.

There is a less elegant way to do that without typing class name twice:

#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;
};

As you can see, in this case macro eats opening { bracket, which will be very misleading.

鲜肉鲜肉永远不皱 2024-09-19 04:00:27

这样的事情怎么样:

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

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

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

how about something of this sort:

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

(first)(second)(...) is a boost preprocessor sequence, which is really single argument as far as your macro is concerned: 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
...\
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文