私はかなり複雑な構成をしています。私はまた、あまりにも長い間それを見つめていたことにかなり確信があり、それらすべての木々が私の森の視界を覆い隠しています. そのため、実際に関連するのはほんの一部に過ぎないと思いますが、構成の完全な複雑さを示します。
さて、私の言葉での構成:
独自の基底クラスから派生したテンプレート化された基底クラスは、いくつかの演算子のオーバーロードを実装します。
テンプレート化された基本クラスからサブクラス化されたクラス (独自の名前をテンプレート パラメーターとして使用) は、すべてのオペレーターにアクセスできます。このコンストラクトは、この質問に従って、演算子が等しい型でのみ操作できることを保証します。
単一の特定のサブクラスは、いくつかの特殊なバージョンの演算子を実装します。このクラスを呼び出し
Derived
ます。このサブクラスも名前付きコンストラクターを使用するため、そのメイン コンストラクターはprivate
です。別の基本クラスは、キャスト演算子 to
double
および to を実装Derived
して、そのサブクラスを (暗黙的に)Derived
型にキャストできるようにします。これらの基底クラスの 1 つを呼び出しますOtherDerived
。のインスタンスは
Derived
、 の名前付きコンストラクタの 1 つを呼び出すか、または のようにDerived
パススルーによって構築できます。OtherDerived
Derived D = OtherDerived(5.0);
私の問題:
定義はの代わりにdouble
Derived D = OtherDerived(5.0) * 2.0;
にキャストOtherDerived(5.0)
するように見えるため、 による乗算は単に double の積であり、inの基本クラスの出力ではありません。Derived
2.0
operator*
Derived
テンプレート化された基本クラスの の定義は
operator*=
、 への参照を返すことはできません*this
。これは、 の型が で*this
あるBaseClass<T>
のに対し、目的の参照の型が だけであるためT&
です。
これらの問題をエレガントに解決するにはどうすればよいですか?
参照をまったく返さないことで簡単に回避できるため、2 番目の問題はマイナーだと考えています。とはいえ、あると良いですね。Derived D = OtherDerived(...) * 2.0
しかし、私にとって最も重要なことは、人々が何かを書くことができるようにするにはどうすればよいかということです。
人々に書くことを要求する
Derived D = (Derived)OtherDerived(...) * 2.0;
、 またDerived D = OtherDerived(...) * Derived::someName(2.0);
、 またDerived D = OtherDerived(...).operator*(2.0);
などはかなり奇妙で不必要に思えます...
NB:できれば、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;
}