1

私はこの設計上の問題に遭遇しました。ストーリーは次のとおりです。

次のようないくつかのメソッドを定義する基本クラスがあります。

virtual double & f(double x);

基本クラスはそれらの1つを呼び出して、いくつかのクエリに応答するときにサブクラス内のいくつかのデータへの参照を要求します。問題は、これらのfメソッドがサブクラスのオプションのデータを返すことです。つまり、サブクラスによっては、fが返すように要求しているものがまったく存在しない場合があります。基本クラスのロジックは、サブクラスが存在しない場合にそのようなf()を呼び出さないことを保証できるため、原則として、このサブクラスはこのメソッドを実装する必要はありませんが、サブクラスはインスタンス化可能である必要があるため、メソッドは純粋な仮想です。不便なことに、fの戻り型は参照である必要があるため、単純にジャンク値を返すことはできません。

したがって、基本的に私はダミー参照を返す「エレガントな」方法を探しています。これは、プログラムが正しく機能していればとにかく呼び出されませんが、理想的には、誤った呼び出しをキャッチすることでデバッグに役立ちます。fの署名は読みやすさにとって重要なので、理想的には変更したくありません。

クラスでダミーのstaticdoubleDATA_NOT_EXIST変数を宣言して返すことができると思いますが、少し見苦しいようです。より良いアイデアはありますか?必要なときに「null」参照を返すためのお気に入りの方法は何ですか?

前もって感謝します。


編集:

これらのメソッドを基本クラスに保持したいのですが、基本クラスはすべてのサブクラスに適用できないロジックを処理しようとしているため(これ自体が悪い設計ですか?)、代わりにサブクラスで宣言した方がよいようです。このようなもの:基本クラスはマウスを表し、サブクラスのオプションのデータは左/中央/右ボタンを表します。特定のサブクラスには特定のボタンがない場合がありますが、ボタンがある場合とない場合があることを前提として、基本クラスはボタンのクリックを処理します。


編集:これが私がやろうとしていることを説明するためのいくつかのソースコードです。基本クラス:

#include <cassert>
struct Base
{
  double & basef(int x)
  {
    assert(x >= 0 && x < 20);
    if (x < 10) return f1(x);
    else return f2(x);
  }
  virtual double & f1(int x);
  virtual double & f2(int x);
};

struct Sub1 : Base
{
  double & f1(int x) { return a[x]; }
  double & f2(int x) { return b[x - 10]; }
  double a[10];
  double b[10];
};

struct Sub2 : Base
{
  double & f1(int x) { return a[x]; }
  double & f2(int x) { /* nothing to return here! */ }
  double a[10];
};
4

2 に答える 2

2

いくつかのオプションがありますが、2つの回答で提案されているように、nullポインターを逆参照して、プログラムに未定義の動作を導入する必要はありません。

1)例外をスローします。予測不可能性を取り除き、それを設計の一部にします。

// default implementation in base class
virtual double& f2(int x)
{
    throw std::runtime_error("No value defined");
}

2)使用boost::optional<double&>

// default implementation in base class
virtual boost::optional<double&> f2(int x)
{
    return boost::optional<double&>();
}

// call-site
auto value = x->f2(0);
if (value)
    do_something(*value);

3)使用double*(貧乏人のboost::optional):

// default implementation in base class
virtual double* f2(int x)
{
    return nullptr;
}

// same call-site as before

4)状況を回避するために、設計を根本的に変更します。

これらはすべて、信頼性が高く予測可能であるため、より優れたソリューションです。

于 2012-10-09T15:15:19.007 に答える
1
double& Dummy() { return *(double*)nullptr; }

コンパイラがこれがnullptrアクセス​​であることを認識して警告するほど賢い場合は、クラッシュを引き起こす可能性のある別の値を使用してみてください。たとえば、4096未満の値を使用してみてください(最近のシステムでは、nullpointerをキャッチするために最初のメモリページを完全にオフリミットにする必要があります) dereferences)、〜0など、またはポインタをグローバル変数にします。

もちろん、私は通常次のようなことをします

double& Dummy() { ASSERT(false); }

コンパイラが返さない関数を認識していない場合にのみ、参照を返します。

于 2012-10-09T09:56:39.903 に答える