C ++返回一个对象抛出一个接口

时间:2011-07-11 14:18:11

标签: c++ interface return-value-optimization

我想设计一个通用接口,它有一个方法可以让我将两个具有此接口的对象相乘,并返回与结果相同的类的新对象。为了保持简单,我将专注于实现此接口的一个类。 问题:我的问题是返回的对象。 我们来看看:

拥有界面之前的目标:

class C {
  public:
  int get() { return v; }
  void set(int value) { v = value; }
  C operator * (C &l) {
    C r;
    r.set(get() * l.get());
    return r;
  }

  private:
  int v;
};

在这种情况下,operator *方法返回一个C类型的对象,但不是引用(请记住这一点)。它利用了返回值优化。 现在,让我们来解决问题: 在这种情况下,我想设计一个界面:

struct I {
  virtual int get() = 0;
  virtual void set(int value) = 0;
  virtual I& operator * (I &l) = 0;
};

在这种情况下,我不能使用返回的类型I(按值)作为operator *方法,因为我是抽象的。好的,我们来看看问题:

class C : public I {
  public:
  int get() { return v; }
  void set(int value) { v = value; }
  I& operator * (I &l) {
    C r;
    r.set(get() * l.get());
    return r; //  warning: reference to local variable ‘r’ returned
  }

  private:
  int v;
};

这里的问题是我正在返回对局部变量的引用。

如何在不使用动态分配的情况下以正确的方式执行此操作?

提前致谢。

5 个答案:

答案 0 :(得分:2)

返回指向动态分配对象(I*)的指针或按值返回C

可以返回引用,但这很令人困惑,所以不要执行以下操作:

virtual I &operator*(I &l) {
    C *r = new C();
    r->set(get() * l.get());
    return *r; //  warning: reference to local variable ‘r’ returned
}

这里的问题是,虽然返回值看起来像一个值,但它仍然必须是delete'd,并带有异常语法delete &r;

答案 1 :(得分:2)

如果不使用动态分配,就不能以这种多态方式执行此操作。

你确定乘法在多态方式中真的有意义吗?如果是这样,您将必须返回动态分配的指针并管理其生命周期(可能使用智能指针)。但是在这种情况下,如果operator*它不符合正常的语义,那么你应该创建一个特殊的函数来完成这项工作。

另请注意,您有一些不是C ++的怪癖 - 惯用语。 get应该是一个const方法,operator*的参数应该是const引用或值(没有人希望operator*修改其操作数之一,因为它违反了最少的意外原则)。通常operator*按值返回其结果,以防止在操作符未按值返回时,对拥有任何已分配的返回内存的人造成混淆。

答案 2 :(得分:1)

我认为在这种情况下你应该使用operator*=而不是operator*

operator*=中,您返回对*this的引用,该引用不是本地变量,因此可以返回。

operator*的情况下,它应该是const,你需要按值返回(好吧,语言不会强迫你,但是如果你正在进行乘法运算,那么它很可能是最明智的要做的事)。我不确定如何使用虚函数来处理这样的事情,我通常会使用模板(尽管使用这种方法会丢失运行时多态性。)

答案 3 :(得分:0)

编辑:您想要的是什么......但这是一个非常糟糕的主意。

无内存分配的要求完全不可能。乘法需要创建一个新对象(根据定义),并且需要在堆上创建多态对象(如果您想避免切片并通过接口引用它)。

但是,如果您仍想使用多态I* result = a*b*c编写a,b,c,则可以使用代理对象并使用一些隐式转换来实现此目的。

您可以创建一个代理对象,其中包含一些隐式转换:

   struct Iref {
      I* ref;
      Iref(I* aref):ref(aref){};
      operator I*() { return ref; }   
      Iref operator * (I& b);
      Iref operator * (Iref b);
      Iref operator * (I* b);
   };

使用此代理和适当编写的方法,您最终可以:

int main()
{
  C a(1), b(2), c(3);
  I* result = a*b*c;
  return 0;
}

剩下的问题是固有的内存泄漏。您可以在应用程序中使用垃圾收集器。我对这些没有经验,我只知道它是可能的。或者让代理对象处理内存释放。

这个相当复杂的技巧应该表明operator*和多态一起不是一个好主意。还有其他问题,因为多态性可能导致a * bb * a结果不同。

答案 4 :(得分:0)

1 - 您无法返回类型为“I”(抽象类型)的对象实例 2 - 如果要返回对象而不是指针,则应使用正常返回类型('C')。其他方式:让'我'不抽象并返回'我' 3 - 推荐方式:只返回I *,不要忘记稍后删除该对象。