c++ - 将抽象类实现为其他类的接口(interface)而无需 vtable 开销

标签 c++ oop c++11 inheritance c++17

我想制作接口(interface)类ForwardIteratorBiderctionalIteratorRandomAccessIterator,它们每个都有一些运算符(它们都是纯虚的并没有实现)。现在如果我想为容器实现一个迭代器,如果我不小心忘记实现一些函数/运算符,我只需继承正确的迭代器并获得编译器的帮助。 用纯虚函数来完成它工作得很好,但它有 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/

相关文章:

c++ - 如何将从 Google AddressSanitizer 抛出的错误记录到日志文件中

c++ - 纯碱基变化

c++ - 如何允许子类具有公共(public)基类但在其方法中接受不同类型的参数

c++ - 有没有办法在不在当前范围内的 lambda 中使用变量?

c++ - 延迟函数模板实例化

c++ - 使用 std::move 在开头插入 vector 的中间元素不起作用

c++ - 组合对象初始化

java - 为什么我不能从事件监听器调用方法,但可以在类的其他地方调用方法?

c++ - 使用公钥 : BER decode error 加密消息

c++ - 根据 1 的数量查找数字的等级