我有一个相当复杂的构造。我也很确定我一直盯着它看太久了,所有这些树现在都掩盖了我对森林的看法。所以我会给你构造的完整复杂性,即使我怀疑它的一小部分实际上是相关的。
现在,我用语言构建:
从其自己的基类派生的模板化基类实现了多个运算符重载。
从模板化基类继承的类(使用自己的名称作为模板参数)将可以访问所有运算符。根据{{3}},此构造确保运算符只能在相同类型上运行。
单个特定子类实现了一些运算符的专用版本。拨打此课程Derived
。此子类还使用命名构造函数,因此其主构造函数为private
。
另一个基类将转换运算符实现为double
和Derived
,以使其子类(隐式)转换为Derived
类型。调用其中一个基类OtherDerived
。
Derived
的实例可以通过调用Derived
中的一个命名构造函数,或者通过OtherDerived
传递Derived D = OtherDerived(5.0);
来构造}}
我的问题:
定义Derived D = OtherDerived(5.0) * 2.0;
似乎将OtherDerived(5.0)
转换为 double 而不是Derived
,因此乘以2.0
只是一个双精度的乘积,而不是operator*
基类中Derived
的输出。
模板化基类中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()
等。看起来很奇怪而且没必要......
注意:最好,#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}}
答案 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