この不自然な例を考えると:
struct point_2d {
point_2d& x( int n ) {
x_ = n;
return *this;
}
point_2d& y( int n ) {
y_ = n;
return *this;
}
int x_, y_;
};
struct point_3d : point_2d {
point_3d& z( int n ) {
z_ = n;
return *this;
}
int z_;
};
int main() {
point_3d p;
p.x(0).y(0).z(0); // error: "point_2d" has no member named "z"
return 0;
}
アイデアは、「メンバー関数チェーン」を使用して、連続して複数のメンバー関数を呼び出すことができるようにすることです。(これには多くの例があります。上記は、この質問をするために私が考えることができる最短の例です。私の実際の問題は同様であり、以下に説明されています。)
問題は、派生クラスが独自の連鎖メンバー関数を追加するが、最初に基本クラスのメンバー関数を呼び出すと、派生クラスのメンバー関数を呼び出すためにはもちろん機能しない基本クラス参照を取得することです。
この問題を解決し、メンバーと関数の連鎖を実行する機能を維持するための賢い方法はありますか?
実際の問題
私の実際の問題は、私の基本クラスが例外であり、私の派生クラスが基本例外から派生したクラスであるということです。これらのクラスについても、メンバー関数チェーンを使用したいと思います。
class base_exception : public std::exception {
// ...
base_exception& set_something( int some_param ) {
// ...
return *this;
}
};
class derived_exception : public base_exception {
// ...
};
int main() {
try {
// ...
if ( disaster )
throw derived_exception( required_arg1, required_arg2 )
.set_something( optional_param );
}
catch ( derived_exception const &e ) {
// terminate called after throwing an instance of 'base_exception'
}
}
問題はそれset_something()
が戻ることですbase_exception
が、catch
期待しderived_exception
ます。もちろん、人間は例外の実際のタイプがであると言うことができますderived_exception
が、コンパイラは明らかにわかりません。
これが私が本当に解決しようとしている問題です。つまり、基本例外クラスが例外オブジェクトにオプションのパラメーターを設定できるようにする一方で、派生型のインスタンスを返す方法です。point_2d
私が上で示した例は、人々が理解できる同じ問題のより小さくて単純なバージョンであり、より小さな問題の解決策も私の実際の問題を解決するだろうと私は信じています。
base_exception
テンプレートを作成して、次のような派生型を渡すことを検討したことに注意してください。
template<class Derived>
class base_exception {
// ...
Derived& set_something( int some_param ) {
// ...
return *this;
}
};
more_derived_exception
実際には問題は解決すると思いますが、別のクラスがから派生した場合derived_exception
、同じ問題に戻るため、完全な解決策ではありません。