質問
オプションの仮想関数を持つ基本クラスがあります
class Base {
virtual void OnlyImplementThisSometimes(int x) {}
};
これをコンパイルすると、未使用のparam 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
<!> quot; int y <!> quot;で派生関数を実装したため、基本クラスメソッドが呼び出されました。 paramですが、これに関する警告はありません。これらはC ++でよくある落とし穴ですか、それとも仮想関数を誤解していますか?
解決
設計の問題を無視すると、変数名を省略することで、未使用の変数に関するコンパイラの警告を回避できます。例:
virtual void OnlyImplementThisSometimes(int ) { }
仮想関数をオーバーライドするときに誤ったメソッドシグネチャを誤って実装することは、C ++で注意する必要があることです。 C#などの言語では、「オーバーライド」キーワードを使用してこれを回避します。
他のヒント
マクロ_unused
を次のように定義します:
#define _unused(x) ((void)x)
次に、関数を次のように定義します。
virtual void OnlyImplementThisSometimes(int x) { _unused( x );}
これにより、コンパイラーが不平を言うのを防ぐだけでなく、xを忘れていないコードを保守している人にとっても明白になります。
基本クラスで定義する理由基本クラスがメソッドを使用しない場合は、派生クラスで仮想メソッドとして定義するだけです。
またはデフォルトの実装は例外をスローする可能性があります
仮想関数のデフォルト実装を提供する場合、その関数をオーバーライドしないすべての派生クラスの正しい実装である必要があります。 正しい実装を提供できない場合は、純粋な仮想関数を作成し、派生クラスに任せて実装を提供することをお勧めします。メソッドの呼び出しを許可しない派生クラスは、例外をスローして、誤って使用されないようにすることができます。
変数名を単に省略することに加えて、多くのコンパイラーでは、コンパイラーに、それが使用されていないことを認識し、これを行うことでSHUTUPを伝えることができます
int func(int x)
{
(void) x;
}
これは私のコードでは多少一般的です。たとえば、シングルスレッド操作およびマルチスレッド操作用に設計されたクラスがあります。多くの一般的なルーチンとデータがあります。これらすべてを基本クラスに配置します(これには純粋な仮想クラスもいくつかあります)。
2つの空の仮想関数、Init()とCleanup()を基本クラスに実装します。シングルスレッドの派生クラスはそれらを暗示しませんが、マルチスレッドのクラスは暗示します。
ファクトリ関数でapproprite派生クラスを作成し、ポインターを返します。クライアントコードは基本クラスタイプのみを認識し、Init()およびCleanup()を呼び出します。どちらのシナリオも正しいことをします。
もちろん、これを行う方法について他の良い提案があるかもしれませんが、このイディオムは私のコードの多くでうまく機能します。
これは悪い習慣ではなく、実装のオプションであるクラスの部分を指定するための一般的なイディオムです。
現在、ユーザー入力システムに使用しています。そのクラスのユーザーがすべてのメソッドを実装するのは面倒だからです。
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) {}
};
ところで、基本クラスを知っていれば、動的な up キャスト、つまり派生からベースへのキャストは一切必要ありません。
Base *b = &d;
同様に実行します。ダウンキャストするとき、つまりベースから派生にdynamic_cast<>
を代わりに使用する必要があります:
if((Derived *d = dynamic_cast<Derived *>(b)) != 0)
{
// use d
}
(もちろん、ダウンキャストの場合、static_cast<>
も通常は機能します。)
これを試してください:
class Base {
virtual void OnlyImplementThisSometimes(int x) = 0;
};
そのようなことをやってからしばらく経ちましたが、それが仮想関数の宣言方法だと思います。
他の人が言ったように、変数名はこのような関数宣言ではオプションです。
これに対する最も簡単な答えを以下に示します:
class Base {
virtual void OnlyImplementThisSometimes(int x) { x;}
};
絶対に何もしない変数への単純な参照は、すべての警告を削除します(とにかく最高レベルのVC ++から)。