我有一个相当复杂的结构。我也很确定我已经盯着它看太久了,所有这些树现在都遮蔽了我对森林的看法。所以我会给你我的构造的全部复杂性,即使我怀疑它实际上只有一小部分是相关的。
现在,我用文字构造:
从它自己的基类派生的模板化基类实现了几个运算符重载。
从模板化基类子类化的类(使用它们自己的名称作为模板参数)将可以访问所有运算符。根据此问题,此构造可确保运算符只能对相同的类型进行操作。
一个特定的子类实现了一些特殊版本的操作符。调用这个类
Derived。这个子类也使用命名构造函数,所以它的主要构造函数是private.另一个基类实现了转换运算符 to
double和 toDerived,以使其子类能够(隐式)转换为Derived类型。调用这些基类之一OtherDerived。Derived然后可以通过调用 中的命名构造函数之一Derived或通过传递来构造OtherDerived的实例Derived D = OtherDerived(5.0);
我的问题:
定义
Derived D = OtherDerived(5.0) * 2.0;似乎强制OtherDerived(5.0)转换为double而不是Derived,因此乘法2.0只是 double 的乘积,而不是operator*inDerived基类的输出。模板化基类中的定义
operator*=不能返回对 的引用*this,因为 的类型*this是BaseClass<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;
}