抽象运算符 +?

发布于 2024-07-27 15:32:11 字数 791 浏览 8 评论 0原文

我有一个类:

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

我真的需要在基类中定义一个运算符 + - 同时需要保持抽象。 我发现很难实现,因为典型的运算符 + 返回一个值,而抽象类无法实例化 - 所以我发现自己陷入了第 22 条陷阱的情况。 对此有有效的解决方案吗?

问候

I've got a class :

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

And a child class that derives from it

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

I really really need to have a operator + defined in the base class - which in the mean time needs to remain abstract. I find it hard to achieve as a typical operator + returns a value, while an abstract class can't be instantiated - so I found myself in a bit of a catch #22 situation.
Is there a valid solution to this ?

Regards

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

肤浅与狂妄 2024-08-03 15:32:14

Operator+() 几乎应该始终作为自由函数实现,因此无需在基类中将其声明为 virtual(您没有这样做,但必须避免语法错误)。

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

Operator+() should almost always be implemented as a free function, so there is no need to declare it virtual (which youu are not doing, but must to avoid a syntax error) in base.

Basically, your design is wrong - if you need some sort of operator+()-like behaviour which a sensible implementation of operator+() cannot really provide, use a named member function instead of operator+().

夢归不見 2024-08-03 15:32:14

我正在此处回复您的问题。 (如果可以的话,删除该“答案”并编辑你的OP)

你应该看看 std::advance,在标头 <迭代器>

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

    // (...)
    return 0;
}

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

I'm replying to your question here. (When you can, delete that "answer" and edit your OP)

You should take a look at std::advance, defined in the header <iterator>.

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

    // (...)
    return 0;
}

If I'm misunderstanding your question, forgive me :P

知足的幸福 2024-08-03 15:32:14

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

解释一下你想要做什么,也许可以找到更好的方法。

If you were allowed to do this, you could write code that doesn't make sense. If you return an abstract class by value, you've just instantiated it, and now you have an object with undefined methods running around. Also, functions have to have a consistent return type, so even your derived classes will be making instances of the abstract base, which is not what you want. There is one exception to consistent return types, covariant return types, but those only apply for pointers.

Explain what you're trying to do, and a better way can probably be found.

羞稚 2024-08-03 15:32:14

大家好,这是另一个帐户上的 OP。

目的
编写一个能够迭代 std::vector 和 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

模板
类 std_iterator :公共迭代器
{
typedef 类型名 C::iterator c_iterator;
民众 :
迭代器 & 运算符 = (const c_iterator & i)
{ m_it = i; 返回*这个; }
迭代器 & 运算符 = (const std_iterator & 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> 它 = my_vector.begin(); // 这个有效
std_iterator> 其他=它; 这个也可以工作

//如果我在上述函数中,

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

Hey all, this is the OP on an alternative account.

THE PURPOSE
To write an universal iterator class family that will be capable of iterating over std::vectors and T[] arrays, where T = byte = unsigned char.

THE IDEA BEHIND THE ABSTRACT CLASS

The idea was to use the base abstract class for function interfaces so that all functions would have a common type . The following abstract class enforces all children classes to employ the following operators :

** I haven't got a compiler with me atm so please forgive any errors my behalf **

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

So an example derived class would look like this :

/*! \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;
};

Apart the forementioned iterator we can have an iterator that will iterate over an std::vector

template
class std_iterator : public iterator
{
typedef typename C::iterator c_iterator;
public :
iterator & operator = (const c_iterator & i)
{ m_it = i; return *this; }
iterator & operator = (const std_iterator & o)
{ m_it = o.m_it; return *this; }

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

private :

c_iterator m_it;

};

Ok, so basically the forementioned iterators are capable of iterating over an array or a vector.

if we were to use a function that has the following interface :

int DoStuff(iterator &it); 

All kinds of iterators would be capable of calling it - and that is the general idea. Let's say that I'm dealing with data coming in a variety of forms - ranging from arrays to vectors :)

Thing is, I need the following functionality :

std_iterator> it = my_vector.begin(); // THIS ONE WORKS
std_iterator> other = it; // THIS ONE WORKS TOO

If I were inside the forementioned function

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;
}
魂牵梦绕锁你心扉 2024-08-03 15:32:14

我们有两个相互冲突的问题:

  1. 您想要使用抽象基类型作为传值类型。
  2. 您实际上需要具有纯虚函数的抽象虚拟行为。

一种解决方案:“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 = other._impl->clone() ,其中clone() 是制作 impl 的深度复制的虚拟函数)或使用智能指针实现。 如果您尝试后者,请确保常量正确并为变异操作制作深层副本。

We have two conflicting problems:

  1. You want to use the abstract base type as a pass-by-value type.
  2. You actually want abstract virtual behavior, with pure virtual functions.

One solution: the "pimpl" or "letter-envelope" idiom. The basic idea: create a class that wraps a pointer to an implementation class:

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

Each virtual method in class impl has a corresponding non-virtual method in the handle. You can pass handles around by value - they're all the same size and construction as their "customization" is done via the impls they point to. And all of the underlying virtual function calls are done via pointer, so you are never creating an instance of a base impl.

You then write subclasses of impl for each specialization that you want.

One issue: you will have to be careful about memory management. You need to write a copy constructor and assignment operator for the handle. What they do with the impl is up to you. The simplest thing is to make a shallow copy of the pointer, but this is likely not sufficient, as you don't know who "owns" the pointer, i.e. when it can be freed. So, you may either have to always deep-copy the impl (i.e. _impl = other._impl->clone() where clone() is a virtual function that makes a deep copy of an impl) or use a smart pointer implementation. If you try the latter, then be sure to be const-correct and make deep copies for mutating operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文