我有一个相当复杂的结构。我也很确定我已经盯着它看太久了,所有这些树现在都遮蔽了我对森林的看法。所以我会给你我的构造的全部复杂性,即使我怀疑它实际上只有一小部分是相关的。
现在,我用文字构造:
从它自己的基类派生的模板化基类实现了几个运算符重载。
从模板化基类子类化的类(使用它们自己的名称作为模板参数)将可以访问所有运算符。根据此问题,此构造可确保运算符只能对相同的类型进行操作。
一个特定的子类实现了一些特殊版本的操作符。调用这个类
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;
}