协变返回类型和右值引用

问题描述

我的目标是在派生类上实现一个运算符,以便返回类型应该是派生类的。

我能够使用以下代码实现它:

#include <iostream>

class Base{
public:
  virtual Base&& operator+ (const Base &b)  = 0;
  virtual void Val() = 0;
};


class Derived : public Base{
public:
  Derived&& operator+ (const Base &b) override
  {
    Derived *res = new Derived;
    auto tmp = dynamic_cast<const Derived*>(&b);
    if(tmp) res->fVal = this->fVal+tmp->fVal;
    return std::move(*res);
  }
  
  void SetVal(double val){fVal = val;}
  void Val() override{std::cout<<"derived:"<<fVal<<std::endl;}
private:
  double fVal{0};
};

int main(){
  Derived a;
  a.SetVal(2);
  Derived b;
  b.SetVal(3);
  Base *baseptr = new Derived(a+b);
  baseptr->Val();
  Base &&d = a+b;
  d.Val();
  Derived e = dynamic_cast<Derived&>(d);
  e.Val();
  return 0;
}

我对返回类型使用右值引用不太满意,所以我想知道是否有我看不到的更简单的解决方案。返回派生类型的副本不起作用,因为 gcc 声明返回类型不是协变的。

编辑:正如@ofo 所提到的,我可以实现非常相似的返回左值引用的东西。目前它是最适合我的选项。但是,仍然不希望(至少可以说)有等待发生的内存泄漏,我只需要对 a+b;

的结果不做任何事情

解决方法

正如@Eljay 所建议的那样,我没有看到一种在不返回指针的情况下实现这一目标的方法。返回引用是可行的,但我认为无法确保调用者删除任何需要删除的内容。

我想到了这个(其中 func 代表我将使用运算符的场景):

#include <iostream>
#include <memory>

class Base{
public:
  virtual std::unique_ptr<Base> operator+(const Base &) = 0;
  virtual void SetVal(double) = 0;
  virtual void Val() = 0;
};


class Derived : public Base{
public:
  std::unique_ptr<Base> operator+(const Base &b) override
  {
    std::unique_ptr<Base> res = std::make_unique<Derived>();
    auto tmp = dynamic_cast<const Derived*>(&b);
    if(tmp) res->SetVal(this->fVal+tmp->fVal);
    else std::cout<<"now i deal with invalid type case"<<std::endl;
    return res;
  }
  
  void SetVal(double val) override{fVal = val;}
  void Val(){std::cout<<fVal<<std::endl;}
private:
  double fVal{0};
};

void func(Base &a,Base &b)
{
  auto res = a+b;
  res->Val();
}

int main(){
  Derived a;
  a.SetVal(2);
  Derived b;
  b.SetVal(3);
  auto d = a+b;
  d->Val();

  func(a,b);
  return 0;
}

如果有人找到更好的解决方案,我会暂时搁置。否则我会将其标记为答案。