2017-02-22 6 views
3

私はこのクラス階層をどのように進めるのかアドバイスを探しています。私はC++で構築しています。C++の関数から継承したクラスを返す最も良い方法

基本クラスは行列である:

class Matrix 
{ 
protected: 

    int rows; 
    int columns; 
    double* values; 

public: 

\\lots of stuff goes here. bla di bla di bla. 

    virtual Matrix operator+(const Matrix& addend) const; 

\\etc. 
} 

はSquarematrixマトリックス

class Squarematrix : public Matrix 
{ 
public: 

    Squarematrix operator+(const Squarematrix& addend) const; 

} 

オペレーター+から継承され、それぞれマトリックスまたはsquarematrixを返します。 operator +は仮想関数なので、すべてのクラスで同じ戻り値の型を持たなければならないため、このコンパイルは実行されません。

私のオプションは何ですか?

私は仮想ではなく普通の関数を使うことができました。これは少し面倒ですが、ほとんどの状況で問題を引き起こすことはありません。

すべての場合に行列を返すことができます。これは基本的に私のsquarematrixクラスを、使用する***の右の痛みにするでしょう。私はmatrixからsquarematrixへと絶えずダウンキャストする必要があります。

私は正方行列への参照を返すことができます。その後、マトリックスはヒープ上に格納されなければならず、安全に削除されることを確実にする方法はありません。私はこのような何かあれば特に:

squarematrix a=b+(c+d); 

(C + D)は、ヒープ上に格納され、漏洩したことになるので、それへのポインタを持っていません。

仮想関数を保持する方法はありますか?また、戻り値の型は変わりませんか?

あなたはこの状況で何をアドバイスしますか?

ありがとうございました。あなたからの返信を楽しみにしています。

+0

いいえ。オーバーライドされた仮想関数は、同じ型を返す必要があります。物語の終わり。この非常に一般的なデザインパターンでは、仮想関数はスマートポインタを基本クラスに返します。クラスが正しく設計されている場合、これはかなりうまく機能します。 –

+1

@SamVarshavchik必ずしもそうではありません。 'clone()'メンバ関数のように、共変な戻り値型を持つのは一般的です。 – juanchopanza

+4

[Circle-ellipse_problem](https://en.wikipedia.org/wiki/Circle-ellipse_problem)をご覧ください。 – Jarod42

答えて

1

これは戻り型共分散(https://en.wikipedia.org/wiki/Covariant_return_type)として知られています。

古いコンパイラではサポートされていませんでしたが、現在は多くの人がサポートしています。例えば、私のコードはVisual Studio 2017でうまくコンパイルされます。ここでは、C++でのその使用法と制限に関する記事があります:https://aycchen.wordpress.com/2009/08/17/covariant-return-type-in-cpp/

まだC#で​​はサポートされていませんが、将来のバージョンで検討されています。 https://github.com/dotnet/csharplang/issues/49を参照してください。

これは新しいバージョンのJavaでもサポートされています。 https://blogs.oracle.com/sundararajan/covariant-return-types-in-javaを参照してください。

実装の問題以外は、多態性言語に追加しない理由はありません。 Javaの実装が不完全でバグが発生する可能性がありますが、エラーが発生する可能性はありません。https://dzone.com/articles/covariant-return-type-abyssalを参照してください。

6

私が推薦する:

  1. Squarematrixを削除します。
  2. コンストラクタをMatrixに追加して正方行列を作成します。
  3. 行列が正方行列かどうかの知識がアプリケーションに役立つ場合は、Matrixにメンバー関数を追加してそのクエリに答えます。

class Matrix 
{ 
    public: 

     Matrix(int r);  // Construct a square matrix. 
     Matrix(int r, int c); // Construct a rectangular matrix. 

     bool isSquareMatrix() const { return (rows == columns); } 

     Matrix operator+(const Matrix& addend) const; 

    private: 

     int rows; 
     int columns; 
     double* values; 

} 
+0

squarematrices(inverse、diagonalise、determinantなど)にしか適用できない関数は、コンパイル時ではなく実行時にチェックする必要があり、型が有効かどうかを調べるため、型の安全性を低下させませんか? –

+0

@ YairHalberstadtはい、そうです。しかし、 'Submatrix'をクラスとして持つ場合を考えてみましょう。 'Matrix *'や 'Matrix&'の行列式を計算するには、オブジェクトの基礎となるものが 'Submatrix'であるかどうかを調べなければなりません。それには 'down_cast'が必要です。それはそれほど良いことではありません。行列式を計算するための 'virtual'関数を提供することができます。しかし、長方形の行列の場合は、何かする必要があります。特定の操作がオブジェクトのサブセットに対してのみ許可され、その違いに対処する必要があるという事実を回避することはありません。 –

関連する問題