类似虚拟的朋友功能?

时间:2018-10-06 16:13:07

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

我想创建类似的界面

class Scalar {
public:
  Scalar() {}
  virtual ~Scalar() {}
  //virtual members operators
  virtual Scalar& operator+() const = 0;
  virtual const Scalar operator-() const;
  virtual Scalar& operator=() = 0;
  virtual Scalar& operator+=() = 0;
  //...
};

我还打算使用一些朋友功能,例如:

    friend const Scalar operator+(const Scalar&, const Scalar&);

但是当我派生抽象类并创建派生类时,出现了一个问题,

class RealNumber: public Scalar {
public:
  friend const RealNumber operator+(const RealNumber&, const RealNumber&);
  //some definitions...
};

根据此逻辑,我需要为从operator+派生的每个新类定义一个新的Scalar朋友重载。有什么办法可以解决这个问题,并避免在所有派生类中声明这些朋友?

2 个答案:

答案 0 :(得分:3)

这是您的问题吗?

我了解您的问题是,您的两个朋友具有完全不同的功能,因为他们具有不同的签名:

friend const Scalar operator+(const Scalar&, const Scalar&);
friend const RealNumber operator+(const RealNumber&, const RealNumber&);

更糟糕的是,选择一个类的外部朋友不会是多态的:将根据编译时类型选择合适的朋友。

如何解决?

首先,您可以考虑重写类本身的运算符(保持签名相同),而不是使用外部重载的朋友。

但这有两个主要挑战:

  • 几乎不可能从算术运算符返回引用,除非您接受副作用,否则副作用将使运算符的行为与预期不同。
  • 您需要应付结合不同种类的标量:如果必须向Scalar添加RealNumber怎么办?这将需要实施double dispatch以应对所有可能的组合。

那么,死胡同?

否,还有其他两种选择,具体取决于您的实际问题:

  • 您真的要在运行时动态组合算术类型吗?如果是,则需要放弃使用C ++运算符的重写方法,并使用interpreter pattern来实现表达式评估器。
  • 如果没有,请考虑使用基于模板的设计,以便编译器在编译时选择适当的专业。
  • 或者受许多可能的朋友及其参数类型组合的影响。

答案 1 :(得分:1)

您可能无法创建虚拟好友函数,但可以创建虚拟运算符(甚至可以$myFriendsData = DB::table('cr_friends as cf') ->where('cf.status', '=', 1) ->join('users as U', function() {}) ->whereRaw( '( CASE WHEN cf.friend_to = ' . auth()->user()->id . ' THEN cf.friend_from = U.id WHEN cf.friend_from = ' . auth()->user()->id . ' THEN cf.friend_to = U.id END )' ) ->select('U.*') ->orderBy('U.id', 'desc') ->get(); 进行此操作)。

考虑以下代码: 警告:这根本不是很好的设计

operator +

在编写此代码时,我发现可能会引发很多缺陷(例如+运算符实际上是在进行减法运算,如果第二个操作数是BB而不是第一个操作数??会怎样)

因此,关于您的问题,您需要Scalars。因此,您可以执行以下方法:

#include <iostream>
using namespace std;

class AA {
private:
    int a;
public:
    AA(int a): a(a) {};
    inline int getA() const { return a; };
    virtual AA operator +(const AA &a) {
        AA res(this->getA() + a.getA());
        return res;
    }
};

class BB: public AA {
    public:
    BB(int a): AA(a) {}
    virtual AA operator +(const AA &a) {
        AA res(this->getA() - a.getA());
        return res;
    }
};

int main() {
    BB tmp(1);
    AA& a = tmp;
    AA b(7);
    cout << (a + b).getA();
    return 0;
}