如何简化 C++ 中的接口声明?
我的接口声明通常(总是?)遵循相同的方案。这是一个例子:
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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
就我个人而言,我会删除复制构造函数声明。您拥有纯虚函数,因此在任何情况下都无法通过切片创建此类的实例。如果派生类由于其所拥有的资源的性质而不可复制;它可以将自己标记为不可复制。
然后我会摆脱受保护的默认构造函数;它不执行任何操作,并且在任何情况下都必须从此类派生,因为您具有纯虚函数,因此它不会阻止任何使用。
尽管标记复制赋值运算符可以防止有人执行
*pBase1 = *pBase2
(实际上是无操作),但我个人并不认为值得费心去阻止它。由于您的类没有数据成员,因此编译器生成的类没有固有的危险,因此实际上取决于用户是否适当地使用对基类的指针或引用。我会选择:
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:
考虑使用基类:
从该基类派生的任何类都将是不可复制的,并且将具有虚拟析构函数。
Consider using a base class:
Any class derived from this base class will be noncopyable and will have a virtual destructor.
IMO,最简单的解决方案是将默认方法放入宏中。像这样:
这样,*.h 文件中的每个类定义只需要一个宏。您将需要额外的宏来在某些 *.cpp 文件中实际声明复制构造函数和赋值运算符,或者您可以将默认的复制构造函数和赋值运算符内联,这会将所有内容包装到单个宏中。
唯一的问题是您需要输入类名两次。
有一种不太优雅的方法可以做到这一点,无需输入两次类名:
如您所见,在这种情况下,宏会吃掉左括号,这将非常具有误导性。
IMO, the easiest solution is to put default methods into macro. Like this:
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:
As you can see, in this case macro eats opening
{
bracket, which will be very misleading.这样的事情怎么样:
(first)(second)(...)
是一个 boost 预处理器序列,就您的宏而言,它实际上是单个参数: http://www.boost.org/doc/libs/1_43_0/libs/预处理器/doc/index.htmlhow about something of this sort:
(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