我想制作接口(interface)类ForwardIterator
、BiderctionalIterator
和RandomAccessIterator
,它们每个都有一些运算符(它们都是纯虚的并没有实现)。现在如果我想为容器实现一个迭代器,如果我不小心忘记实现一些函数/运算符,我只需继承正确的迭代器并获得编译器的帮助。
用纯虚函数来完成它工作得很好,但它有 vtable 的开销,这是不必要的,因为所有代码需要都可以在编译时定义。
template <typename T>
struct ForwardIterator{
virtual T operator++() = 0;
virtual T operator++(int) = 0;
};
template <typename T>
struct BidirectionalIterator: public ForwardIterator<T>{
virtual T operator--() = 0;
virtual T operator--(int) = 0;
};
template <typename T>
struct RandomAccessIterator: public Bidirectional<T>{
virtual T operator+(int) = 0;
virtual T operator-(int) = 0;
};
// Custom Iterator Implementation
class MyCustomRandomAccessIterator
: public RandomAccessIterator<MyCustomRandomAccessIterator>{
// get errors if I miss some function definitions.
// but it has vtable !!!
};
最佳答案
如果我没理解错的话,你想确保在最终的派生类中实现了一些方法,但不使用经典方式(抽象继承),因为它太重了。
我的第一个想法是简单地声明而不是定义方法
template <typename T>
struct ForwardIterator {
T operator++ ();
T operator++ (int);
};
所以当你使用这些方法时
MyCustomRandomAccessIterator i;
++i;
您收到链接器错误。
但是你会得到一个链接器错误(我想你更喜欢编译错误)并且只有当你使用一个被遗忘的方法时,所以如果你忘记了一个单一的方法可能很难检测到它(你需要将它与一个对象一起使用) .
所以我的想法,也许并不完美,是删除
方法,添加一个构造函数并检查最终类中的方法是否存在。
我的意思是……某事
template <typename T>
struct ForwardIterator {
T operator++ () = delete;
T operator++ (int) = delete;
ForwardIterator ()
{
static_assert( sizeof(decltype(std::declval<T>()++)), "!" );
static_assert( sizeof(decltype(++std::declval<T>())), "!" );
}
};
这样你就可以得到所有的编译错误(也许,如果你愿意,有有意义的错误信息,比 "!"
更好)简单地声明你的类的一个对象
MyCustomRandomAccessIterator i;
// ++i; // no needs of invoke the forgotten methods to get the errors
下面是一个完整的编译示例
#include <utility>
template <typename T>
struct ForwardIterator {
T operator++ () = delete;
T operator++ (int) = delete;
ForwardIterator ()
{
static_assert( sizeof(decltype(std::declval<T>()++)), "!" );
static_assert( sizeof(decltype(++std::declval<T>())), "!" );
}
};
template <typename T>
struct BidirectionalIterator: public ForwardIterator<T> {
T operator-- () = delete;
T operator-- (int) = delete;
BidirectionalIterator ()
{
static_assert( sizeof(decltype(std::declval<T>()--)), "!" );
static_assert( sizeof(decltype(--std::declval<T>())), "!" );
}
};
template <typename T>
struct RandomAccessIterator: public BidirectionalIterator<T>{
T operator+ (int) = delete;
T operator- (int) = delete;
RandomAccessIterator ()
{
static_assert( sizeof(decltype(std::declval<T>()+0)), "!" );
static_assert( sizeof(decltype(std::declval<T>()-0)), "!" );
}
};
// Custom Iterator Implementation
struct MyCustomRandomAccessIterator
: public RandomAccessIterator<MyCustomRandomAccessIterator> {
// with `if 0` (forgetting definition of requested methods) you get
// a lot of compilation errors
#if 1
MyCustomRandomAccessIterator operator++ ()
{ return *this; }
MyCustomRandomAccessIterator operator++ (int)
{ return *this; }
MyCustomRandomAccessIterator operator-- ()
{ return *this; }
MyCustomRandomAccessIterator operator-- (int)
{ return *this; }
MyCustomRandomAccessIterator operator+ (int)
{ return *this; }
MyCustomRandomAccessIterator operator- (int)
{ return *this; }
#endif
};
int main()
{
// simply declaring i you get a lot of errors, in case of no
// methods definitions
MyCustomRandomAccessIterator i;
}
关于c++ - 将抽象类实现为其他类的接口(interface)而无需 vtable 开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65447631/