抽象运算符+?

时间:2009-07-21 14:43:13

标签: c++ operator-overloading abstract-class

我上课了:

class base
{
public :
 base & operator +=(const int value) = 0;
 // base operator + (const int val) = 0; // HOW DO I DO THIS ?
};

一个源自它的子类

class derived : public base
{
public :
 derived() : m_val(0) {}
 derived(const derived & val) : m_val(val.m_val) {}
 base & operator = (const derived& value) // POSSIBLE TO RETURN A REFERENCE TO BASE
 { m_val = value.m_val; return *this; }
 base & operator +=(const int val)
 { m_val += val; return *this; }
 /* operator + overload here */
 // base operator + (...) // IMPOSSIBLE TO RETURN A VALUE
protected :
int m_val;
};

我真的需要在基类中定义一个运算符+ - 同时需要保持抽象。我觉得很难实现,因为典型的operator +返回一个值,而抽象类不能实例化 - 所以我发现自己处于一个陷阱#22的情况。 有没有一个有效的解决方案呢?

此致

5 个答案:

答案 0 :(得分:10)

运算符+()几乎总是应该作为自由函数实现,因此不需要在base中声明它是虚拟的(你没有做,但必须避免语法错误)。

基本上,你的设计是错误的 - 如果你需要某种类型的operator +() - 类似于operator +()无法实际提供的行为,请使用命名成员函数而不是operator +()。

答案 1 :(得分:1)

我正在回答你的问题here。 (如果可以,请删除“回答”并编辑您的OP)

您应该查看标题std::advance中定义的<iterator>

int DoStuff(iterator &it)
{
    iterator a = it;
    std::advance(a, 2);

    // (...)
    return 0;
}

如果我误解了你的问题,请原谅我:P

答案 2 :(得分:0)

如果您被允许这样做,您可以编写没有意义的代码。如果按值返回一个抽象类,那么你只是实例化它,现在你有一个带有未定义方法的对象。此外,函数必须具有一致的返回类型,因此即使您的派生类也将创建抽象基类的实例,这不是您想要的。一致的返回类型有一个例外,covariant return types,但那些只适用于指针。

解释你正在尝试做什么,并且可能找到更好的方法。

答案 3 :(得分:0)

嘿所有,这是替代帐户的OP。

目的 编写一个通用的迭代器类系列,它能够遍历std :: vectors和T []数组,其中T = byte = unsigned char。

抽象类背后的理念

这个想法是使用函数接口的基本抽象类,以便所有函数都有一个共同的类型。以下抽象类强制所有子类使用以下运算符:

**我没有编译器与我联系所以请原谅我代表的任何错误**

class iterator
{
  public :
    virtual iterator & operator -- ()    = 0;
    virtual iterator & operator -- (int) = 0;
    virtual iterator & operator ++ ()    = 0;
    virtual iterator & operator ++ (int) = 0;
    virtual iterator & operator += (int n) = 0;
    virtual iterator & operator -= (int n) = 0;
    virtual bool operator == (const iterator & o) = 0;
    virtual bool operator != (const iterator & o) = 0;
};

因此,示例派生类看起来像这样:

/*! \brief ptr iterator can be used to iterate over classic c-style arrays */
class ptr_iterator : public iterator
{
  public :
    ptr_iterator() : m_p(NULL) {}
    ptr_iterator(byte * b) : m_p(b) {}

    iterator & operator = (const ptr_iterator &o)
    { m_p = o.m_p; return *this; }
    iterator & operator = (byte * b)
    { m_p = b; return *this; }
    virtual iterator & operator -- ()
    { --m_p; return *this; }
    virtual iterator & operator -- (int)
    { m_p--; return *this; }
    virtual iterator & operator ++ ()
    { ++m_p; return *this; }
    virtual iterator & operator ++ ()
    { m_p++; return *this; }
    virtual iterator & operator += (int n)
    { m_p += n; return *this; }
    virtual iterator & operator -= (int n)
    { m_p -= n; return *this; }
    virtual bool operator == (const iterator & o)
    { return ((ptr_iterator*)&o)->m_p == m_p; }
    virtual bool operator != (const iterator & o)
    { return ((ptr_iterator*)&o)->m_p != m_p; }

  private :
    byte * m_p;
};

除了前面提到的迭代器,我们可以有一个迭代器来迭代std :: vector

模板 class std_iterator:public iterator {   typedef typename C :: iterator c_iterator;   上市 :     迭代器和operator =(const c_iterator&amp; i)     {m_it = i;返回*这个; }     迭代器和operator =(const std_iterator&amp; o)     {m_it = o.m_it;返回*这个; }

virtual iterator & operator ++ ()
{ ++m_it; return *this; }
virtual iterator & operator ++ (int)
{ m_it++; return *this; }
virtual iterator & operator -- ()
{ --m_it; return *this; }
virtual iterator & operator -- (int)
{ m_it--; return *this; }
virtual iterator & operator += (int n)
{ m_it += n; return *this; }
virtual iterator & operator -= (int n)
{ m_it -= n; return *this; }

virtual bool operator == (const iterator &o)
{ return ((std_iterator*)&o)->m_it == m_it; }
virtual bool operator != (const iterator &o)
{ return ((std_iterator*)&o)->m_it != m_it; }
bool operator == (const c_iterator &i)
{ return m_it == i; }
bool operator != (const c_iterator &i)
{ return m_it != i; }

私人:

c_iterator m_it;

};

好的,基本上前面提到的迭代器能够遍历数组或向量。

如果我们要使用具有以下界面的函数:

int DoStuff(iterator &it); 

所有类型的迭代器都能够调用它 - 这就是一般的想法。假设我正在处理各种形式的数据 - 从数组到向量:)

事情是,我需要以下功能:

std_iterator&GT; it = my_vector.begin(); //这一个工作 std_iterator&GT;其他=它; //这一个工作太多了

如果我在前面提到的功能中

int DoStuff(iterator &it)
{
  iterator a = it + 2;   // THIS IS ILLEGAL DUE TO ABSTRACT-NESS OF THE BASE CLASS
                         // YET I STILL NEED THIS TO WORK. HOW DO I ACHIEVE THAT ?
                         // DO I SACRIFICE THE ABSTRACT-NESS OF THE BASE CLASS ?
                         // AT THIS POINT I WAS SERIOUSLY CONSIDERING AN OVERLOAD OF THE
                         // + OPERATOR BUT HAVE NO IDEA HOW TO DO IT WITH AN ABSTRACT 
                         // CLASS 
  // (...)
  return 0;
}

答案 4 :(得分:0)

我们有两个相互矛盾的问题:

  1. 您希望将抽象基类型用作值传递类型。
  2. 您实际上想要使用纯虚函数的抽象虚拟行为。
  3. 一种解决方案:“pimpl”或“letter-envelope”成语。基本思想:创建一个包装指向实现类的指针的类:

    class impl {
    public:
      virtual impl *do_add(const impl *other) const = 0;
    };
    
    class handle {
      impl *_impl;
      handle(impl *i): _impl(i) {}
    public:
      handle(): _impl(NULL) {}
    
      handle operator+(const handle &other) const {
        impl *new_impl = _impl->do_add(other._impl);
        return handle(new_impl);
      }
    };
    

    类impl中的每个虚方法在句柄中都有一个对应的非虚方法。您可以通过值传递句柄 - 它们的大小和结构都与它们的“自定义”相同,都是通过它们指向的impl来完成的。并且所有底层虚函数调用都是通过指针完成的,因此您永远不会创建基本impl的实例。

    然后为每个你想要的专业化编写impl的子类。

    一个问题:您必须小心内存管理。您需要为句柄编写复制构造函数和赋值运算符。他们用impl做什么取决于你。最简单的方法是制作指针的浅表副本,但这可能是不够的,因为你不知道谁“拥有”指针,即何时可以释放它。因此,您可能必须始终对impl进行深层复制(即_impl = other._impl-&gt; clone(),其中clone()是一个虚函数,它生成impl的深层副本)或使用智能指针实现。如果你尝试后者,那么一定要保持正确,并为变异操作制作深层副本。