3

我有一个相当复杂的结构。我也很确定我已经盯着它看太久了,所有这些树现在都遮蔽了我对森林的看法。所以我会给你我的构造的全部复杂性,即使我怀疑它实际上只有一小部分是相关的。

现在,我用文字构造:

  • 从它自己的基类派生的模板化基类实现了几个运算符重载。

  • 从模板化基类子类化的类(使用它们自己的名称作为模板参数)将可以访问所有运算符。根据此问题,此构造可确保运算符只能对相同的类型进行操作。

  • 一个特定的子类实现了一些特殊版本的操作符。调用这个类Derived。这个子类也使用命名构造函数,所以它的主要构造函数是private.

  • 另一个基类实现了转换运算符 todouble和 to Derived,以使其子类能够(隐式)转换为Derived类型。调用这些基类之一OtherDerived

  • Derived然后可以通过调用 中的命名构造函数之一Derived或通过传递来构造OtherDerived的实例Derived D = OtherDerived(5.0);

我的问题:

  1. 定义Derived D = OtherDerived(5.0) * 2.0;似乎强制OtherDerived(5.0)转换为double而不是Derived,因此乘法2.0只是 double 的乘积,而不是operator*inDerived基类的输出。

  2. 模板化基类中的定义operator*=不能返回对 的引用*this,因为 的类型*thisBaseClass<T>,而所需的引用类型只是T&

如何优雅地解决这些问题?

我认为第二个问题是次要的,因为我可以通过根本不返回引用来轻松解决它。不过,有一个也不错。但对我来说最重要的是:我如何让人们能够书写Derived D = OtherDerived(...) * 2.0或类似的、简单的形式?

要求人们写作

  • Derived D = (Derived)OtherDerived(...) * 2.0;, 或者
  • Derived D = OtherDerived(...) * Derived::someName(2.0);, 或者
  • Derived D = OtherDerived(...).operator*(2.0);

等等似乎相当奇怪和不必要......

注意:最好是operator double()剩余的可用:)

这是一个 MWE:

#include <iostream>
#include <cmath>

class SuperBase
{
public:
    virtual ~SuperBase(){}
    SuperBase() : value(0.0) {}

protected:
    double value;
    SuperBase(double value) : value(value) {}
};

template <class T>
class Base : public SuperBase
{
public:
    virtual ~Base(){}
    Base() : SuperBase() {}

    T& operator*=(double F)       { value *= F; return *this; }
    T  operator* (double F) const { return T(value*F); }

    double operator*(const T& U) const {
        return value*U.value;
    }

protected:
    double value;
    Base(double value) : SuperBase(value) {}
};

class Derived final : public Base<Derived>
{
public:

    ~Derived(){}
    Derived() : Base<Derived>(){}

    static Derived someName(double value) {
        return Derived(value);
    }

    Derived operator*(const Derived& D) const {
        return Derived(value/D.value);
    }

private:
    Derived(double value) : Base<Derived>(value) {}
};




class OtherBase
{
public:
    virtual ~OtherBase(){}

    operator double () { return value; }
    operator Derived() { return Derived::someName(value); }

protected:
    double value;
};

class OtherDerived final : public OtherBase
{
public:
    ~OtherDerived(){}

    OtherDerived(double value){
        this->value = std::sqrt(value);
    }
};



int main(int argc, char *argv[])
{
    Derived a = OtherDerived(1.05);     // Compiles fine

    Derived b = OtherDerived(1.05);     // Compiles fine
    b *= 2.0;                           // Error: cannot cast Base<Derived>
                                        // to Derived

    Derived c = OtherDerived(1.05)*2.0; // Error: casts the
                                        // OtherDerived to double,
                                        // so Derived(double) gets
                                        // called, which is private

    return 0;
}
4

3 回答 3

1

Derived::operator*隐藏Base::operator*using Base::operator*尝试在课堂上插入Derivedoperator*(double)Derived.

于 2012-10-16T09:01:10.813 回答
1

对于问题 #1,您可以实现一个独立的乘法运算符:

Derived operator*(const OtherDerived& op1, double op2)
  {
  return (Derived)val1*Derived::someName(val2);
  }

此外,两个转换运算符都OtherBase应该是const.

于 2012-10-16T09:03:53.947 回答
1

如果您的代码#2 main,您的问题似乎源于您希望您的类在构造函数为私有时在内部Base<Derived>创建一个Derived对象......您必须使该类成为朋友才能要调用的构造函数。Base<Derived>::operator*=DerivedBase<Derived>Derived

对于您的main代码的案例#3,我会operator*为您的OtherBaseorOtherDerived类定义一个以防止隐式转换为double.

于 2012-10-16T09:06:11.930 回答