9

オプションの仮想関数を持つ基本クラスがあります

class Base {
    virtual void OnlyImplementThisSometimes(int x) {}
};

これをコンパイルすると、未使用のパラメーター x に関する警告が表示されます。仮想機能を実装する必要がある他の方法はありますか? 私は次のように書き直しました。

class Base {
    virtual void OnlyImplementThisSometimes(int x) 
    {
        x = 0;
    }
};

注意しないと、作成したサブクラスが間違った関数を実装する可能性があり、オーバーロードのために気付かないという問題もあります。

class Derived : public Base {
    void OnlyImplementThisSometimes(int x, int y) { // some code }
};

Derived d;
Base *b = dynamic_cast<Base *>(&d);
b->OnlyImplementThisSometimes(x); // calls the method in the base class

「int y」パラメーターを使用して派生関数を実装したため、基本クラスのメソッドが呼び出されましたが、これに関する警告はありません。これらは C++ でよくある落とし穴ですか、それとも仮想関数を誤解していますか?

4

10 に答える 10

22

変数名を省略して、未使用の変数に関するコンパイラの警告を回避できる設計上の問題を無視します。次に例を示します。

virtual void OnlyImplementThisSometimes(int ) { }

仮想関数をオーバーライドしようとするときに間違ったメソッド シグネチャを誤って実装することは、C++ で注意する必要があることです。C# などの言語は、'override' キーワードを使用してこれを回避します。

于 2008-11-04T00:09:54.463 に答える
11

マクロ_unusedを次のように定義します。

#define _unused(x) ((void)x)

次に、関数を次のように定義します。

virtual void OnlyImplementThisSometimes(int x) { _unused( x );}

これは、コンパイラが文句を言わないようにするだけでなく、x について忘れていないことをコードを保守している人に明らかにします。つまり、x を意図的に無視しています。

于 2008-11-04T00:53:03.843 に答える
6

なぜ基本クラスで定義するのですか? 基本クラスがメソッドを使用しない場合は、派生クラスで仮想メソッドとして定義するだけです。

または、デフォルトの実装が例外をスローする可能性があります

于 2008-11-04T00:04:02.057 に答える
4

仮想関数の既定の実装を提供する場合、その関数をオーバーライドしないすべての派生クラスの正しい実装である必要があります。正しい実装を提供できない場合は、純粋な仮想関数を作成し、派生クラスに任せて実装を提供することをお勧めします。メソッドの呼び出しを許可しない派生クラスは、例外をスローして、誤って使用されないようにすることができます。

于 2008-11-04T00:04:38.390 に答える
3

単純に変数名を省略することに加えて、多くのコンパイラでは、これを実行することで、それが使用されていないことを認識し、SHUTUP することをコンパイラに伝えることができます。

int func(int x)
{
   (void) x;
}
于 2008-11-04T00:14:39.523 に答える
2

ところで、基本クラスを知っていれば、動的なアップキャスト、つまり派生から基本へのキャストを行う必要はまったくありません。

Base *b = &d;

同様に行います。dynamic_cast<>代わりに、ベースから派生にダウンキャストするときに使用する必要があります。

if((Derived *d = dynamic_cast<Derived *>(b)) != 0)
{
  // use d
}

(そしてもちろん、ダウンキャストの場合、static_cast<>通常は同様に機能します。)

于 2008-11-04T00:50:10.700 に答える
2

これは、私のコードではやや一般的です。たとえば、シングルスレッド操作とマルチスレッド操作用に設計されたクラスがあります。多くの一般的なルーチンとデータがあります。私はそのすべてを基本クラスに入れました(これには純粋な仮想もいくつかあります)。

基本クラスに、Init() と Cleanup() という 2 つの空の仮想関数を実装します。シングルスレッドの派生クラスはそれらを実装していませんが、マルチスレッドの派生クラスは実装しています。

ファクトリ関数に適切な派生クラスを作成させてから、ポインターを返します。クライアント コードは基本クラスの型のみを認識し、Init() と Cleanup() を呼び出します。どちらのシナリオも正しいことを行います。

もちろん、これを行う方法については他にも良い提案があるかもしれませんが、このイディオムは私のコードの多くでうまく機能します。

于 2008-11-04T00:12:33.473 に答える
2

これは悪い習慣ではなく、実装がオプションのクラスの部分を指定するための一般的なイディオムです。

現在、私はそれをユーザー入力システムに使用しています。そのクラスのユーザーがすべてのメソッドを実装するのは面倒なので、とにかく使用しない可能性が高いからです。

class mouse_listener{
public:
    virtual ~mouse_listener() {}

    virtual void button_down(mouse_button a_Button) {}
    virtual void button_up(mouse_button a_Button) {}
    virtual void scroll_wheel(mouse_scroll a_Scroll) {}
    virtual void mouse_move_abs(math::point a_Position) {}
    virtual void mouse_move_rel(math::point a_Position) {}
};
于 2008-11-04T00:18:23.133 に答える
-1

これを試して:

class Base {
    virtual void OnlyImplementThisSometimes(int x) = 0;
};

そのようなことをしてからしばらく経ちましたが、それが仮想関数を宣言する方法だと思います。

また、他の人が言ったように、このような関数宣言では変数名はオプションです。

于 2008-11-05T20:51:04.737 に答える
-2

これに対する最も簡単な答えを以下に示します。

class Base {
    virtual void OnlyImplementThisSometimes(int x) { x;}
};

まったく何もしない変数への単純な参照は、すべての警告を削除します (とにかく最高レベルの VC++ から)。

于 2008-11-04T09:30:44.237 に答える