在没有vtable开销的情况下将抽象类实现为其他类的接口 [英] Implementing an abstract class as a interface for other classes without vtable overhead

查看:42
本文介绍了在没有vtable开销的情况下将抽象类实现为其他类的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建接口类 ForwardIterator BiderctionalIterator RandomAccessIterator ,它们每个都有一些运算符(它们都是纯虚拟的)尚未实施).现在,如果我想为容器实现一个迭代器,那么我只是从正确的迭代器继承而来,如果我偶然忘记实现某些函数/运算符,则可以得到编译器的帮助.使用纯虚拟函数可以很好地完成此操作,但是它具有vtable的开销,这是不必要的,因为所有代码需求都可以在编译时定义.

I want to make interface classes ForwardIterator, BiderctionalIterator and RandomAccessIterator, each one of them has some operators (all of them are pure virtual and not implemented). Now if I want to implement an iterator for a container, I just inherit from the right iterator and get the help of the compiler if I accidently forgot to implement some functions/operators. Doing it with pure virtual functions works perfectly but It has the overhead of vtable which is unnecessary since the all code needs can be defined in compile time.

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 !!!

};

推荐答案

如果我理解正确,则希望确保某些方法在最终派生类中实现,但无需使用经典方法(抽象继承),因为它也是如此重.

If I understand correctly, you want to be sure that some methods are implemented in the final derived classes but without using the classic way (abstract inheritance) because it's too heavy.

我的第一个想法只是声明而不定义方法

My first idea was simply declare and not define the methods

template <typename T>
struct ForwardIterator {
    T operator++ ();
    T operator++ (int);
};

所以当您使用方法时

MyCustomRandomAccessIterator  i;

++i;

您收到链接器错误.

但是您会收到一个链接器错误(并且我想您更喜欢编译错误),并且仅在使用被遗忘的方法时才会出现,因此,如果您忘记了一个方法,则很难检测到它(您需要将其与对象一起使用)

But you get a linker error (and I suppose you prefer a compilation error) and only when you use a forgotten method, so if you forget a single method can be difficult detect it (you need to use it with an object).

所以我的想法,也许不是完美的,是删除方法,添加构造函数并检查最终类中方法的存在.

So my idea, maybe not perfect, is delete the methods, add a constructor and check the existence of the methods in the final class.

我的意思是...类似

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>())), "!" );
     }
};

这样,您只需声明类的对象即可得到所有编译错误(也许,如果想要的话,带有有意义的错误消息,比!" 更好)

This way you get all compilation errors (maybe, if you want, with meaningful error messages, better than "!") simply declaring an object of your class

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

这篇关于在没有vtable开销的情况下将抽象类实现为其他类的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆