隐式转换模糊了重载运算符。怎么解决?

时间:2012-10-16 08:51:56

标签: c++ oop design-patterns operator-overloading

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

现在,我用语言构建:

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

  • 从模板化基类继承的类(使用自己的名称作为模板参数)将可以访问所有运算符。根据{{​​3}},此构造确保运算符只能在相同类型上运行。

  • 单个特定子类实现了一些运算符的专用版本。拨打此课程Derived。此子类还使用命名构造函数,因此其主构造函数为private

  • 另一个基类将转换运算符实现为doubleDerived,以使其子类(隐式)转换为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只是一个双精度的乘积,而不是operator*基类中Derived的输出。

  2. 模板化基类中operator*=的定义无法返回对*this的引用,因为*this的类型为BaseClass<T>,而所需类型为T&引用只是Derived D = OtherDerived(...) * 2.0

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

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

    要求人们写作

    • Derived D = OtherDerived(...) * Derived::someName(2.0);
    • Derived D = OtherDerived(...).operator*(2.0);
    • operator double()

    等。看起来很奇怪而且没必要......

    注意:最好,#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; } 仍可用:)

    这是一个MWE:

    {{1}}

3 个答案:

答案 0 :(得分:1)

Derived::operator*隐藏Base::operator*。尝试在课程using Base::operator*中插入Derived,以便在operator*(double)中提供Derived

答案 1 :(得分:1)

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

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

此外,OtherBase中的两个转换运算符都应为const

答案 2 :(得分:1)

如果您的main代码排在第2位,那么您的问题似乎源于您希望Base<Derived>班级在Derived内创建Base<Derived>::operator*=对象的事实当Derived的构造函数是私有的时......你必须使Base<Derived>类成为Derived的朋友才能调用构造函数。

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