【问题标题】:How to declare operator++(int) in an abstract class?如何在抽象类中声明 operator++(int)?
【发布时间】:2020-07-29 18:58:53
【问题描述】:

我有一个抽象类,它基本上是用作“迭代器接口”。也就是说,它是一个抽象迭代器,一些具体的类稍后会实现。为了使抽象类成为迭代器,我需要重载T operator++(int),其中T 是运算符重载的类。

class AbstractClass {
    virtual AbstractClass operator++(int) = 0; // compile time error
    virtual AbstractClass& operator++() = 0;   // but this is fine
}

但是,我不能写 AbstractClass operator++(int),因为只有指针和对抽象类的引用才允许作为返回值。

有没有办法要求子类在纯 C++11 中重载 operator++(int)?

【问题讨论】:

  • 你不是已经需要重写它以便能够创建子类的实例吗? (因为它是一个纯虚方法)
  • @anishsane,这表示后增量而不是前增量。
  • 我不认为这是可以做到的。派生类型是运行时抽象的,返回类型是编译时的。做到这一点的唯一方法是让AbstractClass 仅假装是抽象的。
  • “我有一个抽象类,它基本上是用作“迭代器接口”。我认为是 Java 难民?
  • 您可能还想阅读Why can't I do polymorphism with normal variables? Tour Q 应该作为一个被引用的骗子关闭。

标签: c++ c++11 abstract-class


【解决方案1】:

具有virtual 成员的抽象类通常通过基指针访问,因此调用者不知道派生类型,但调用者必须在编译时知道来自operator++(int) 的返回值,所以没有直接执行此操作的方法。我根本不会提供这种方法,并让你的类类似于迭代器,但不完全符合迭代器。

但是,有一个复杂的解决方法,那就是创建一个非抽象迭代器,它本身可以将虚拟迭代器作为成员处理。这变得超级复杂。

//abstract interface for iterators
template<class value_type>
struct virtual_iterator_interface {
    virtual ~virtual_iterator_interface(){};
    virtual std::unique_ptr<virtual_iterator_interface> clone()const=0;
    virtual value_type& deref()=0;
    virtual void increment()=0;
};
//wrapper implementation for iterators
template<class value_type, class It>
struct virtual_iterator : virtual_iterator_interface<value_type> {
    It it;
    virtual_iterator(It it_) : it(it_) {}
    std::unique_ptr<virtual_iterator_interface> clone()const
    {return std::make_unique<virtual_iterator>(it);}
    value_type& deref()
    {return *it;}
    void increment()
    {return ++it;}
};

static const struct from_iterator_t {} from_iterator;
// The iterator that holds a pointer to an abstracted iterator
template<class value_type>
class erased_iterator {
    std::unique_ptr<virtual_iterator_interface<value_type>> ptr;
public:
    template<class It>
    erased_iterator(from_iterator_t, It it)
    :ptr(std::make_unique<virtual_iterator<value_type,It>>(it)) {}
    erased_iterator(std::unique_ptr<virtual_iterator_interface<value_type>> ptr_)
    :ptr(std::move(ptr_)) {}
    erased_iterator(const erased_iterator& rhs)
    :ptr(rhs.ptr->clone()) {}
    erased_iterator(erased_iterator&& rhs) = default;
    erased_iterator& operator=(const erased_iterator& rhs)
    {ptr=rhs.ptr->clone();}
    erased_iterator& operator=(erased_iterator&& rhs) = default;

    //TADA! Iterator things are now possible!
    value_type& operator*(){return ptr->deref();}
    erased_iterator& operator++(){ptr->increment(); return *this;}
    erased_iterator operator++(){erased_iterator t(it->clone()); ptr->increment(); return t;}
};

除了复杂性之外,这还会在堆上分配迭代器,这使得它们非常很慢。

另请注意:virtual 成员会阻止内联和优化,因此会使代码变慢。对于应该是轻量级的迭代器之类的东西,这实际上会使代码很多变慢。

【讨论】:

  • 我不太明白“具有虚拟成员的抽象类运行时擦除派生类型,但必须在编译时知道 operator++(int) 的返回值。”什么类型被谁擦除?另外,如果在运行时擦除了任何类型,那么它在编译时是已知的,不是吗?
  • @foki: 构造实例的代码在编译时就知道类型,但是调用方法的代码通过基指针调用它,并且不知道类型,即使在编译时.我将其改写为更清晰。
猜你喜欢
  • 2014-02-26
  • 2016-05-10
  • 2011-01-23
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 1970-01-01
相关资源
最近更新 更多