26

オーバーライドされたメソッドの前にvirtualキーワードを付けるのか、それとも元の基本クラスでのみ接頭辞を付けるのかについて、同僚と話し合っています。

私はすべての仮想メソッド(つまり、vtableルックアップを含むメソッド)の前にvirtualキーワードを付ける傾向があります。私の理論的根拠は3つあります。

  1. C ++にオーバーライドキーワードがない場合、仮想キーワードの存在は、少なくともメソッドがルックアップを含み、理論的にはさらなる特殊化によってオーバーライドされるか、より高い基本クラスへのポインターを介して呼び出される可能性があることを通知します。

  2. このスタイルを一貫して使用するということは、仮想キーワードのないメソッド(少なくともコード内)を見ると、最初はそれがベースから派生したものでも、サブクラスに特化したものでもないと想定できることを意味します。

  3. 何らかのエラーによって仮想がIFooから削除された場合でも、すべての子は引き続き機能します(CFooSpecialization :: DoBarは、単に非表示にするのではなく、CFooBase :: DoBarをオーバーライドします)。

私が理解したように、この慣行に反対する議論は、「しかし、その方法は仮想的ではない」(これは無効であり、仮想性の誤解から生まれたと私は信じている)、そして「仮想キーワードを見ると、誰かがそれから派生していて、それらを探しに行くことを意味します。」

架空のクラスは複数のファイルに分散している可能性があり、いくつかの専門分野があります。

class IFoo {
public:
    virtual void DoBar() = 0;
    void DoBaz();
};

class CFooBase : public IFoo {
public:
    virtual void DoBar(); // Default implementation
    void DoZap();
};


class CFooSpecialization : public CFooBase {
public:
    virtual void DoBar(); // Specialized implementation
};

様式的には、2つの派生クラスから仮想キーワードを削除しますか?もしそうなら、なぜですか?ここでStackOverflowの考えは何ですか?

4

6 に答える 6

23

私はあなたの論理的根拠に完全に同意します。メソッドが呼び出されると、動的ディスパッチセマンティクスを持つことを忘れないでください。あなたの同僚が使用している「その方法は仮想ではない」という議論は完全に偽物です。彼は仮想と純粋仮想の概念を混同しています。

于 2009-09-03T01:12:56.623 に答える
6

かつては仮想だった関数は常に仮想です。

したがって、いずれにしても、virtualキーワードが後続のクラスで使用されない場合でも、関数/メソッドが「仮想」になること、つまりオーバーライドされることを妨げることはありません。ですから、私が取り組んだプロジェクトの1つには、私がやや気に入った次のガイドラインがありました。

  • 関数/メソッドがオーバーライドされることになっている場合は、常に「virtual」キーワードを使用してください。これは、インターフェイス/基本クラスで使用する場合に特に当てはまります。
  • 派生クラスがさらに明示的にサブクラス化されることになっている場合は、オーバーライドできるすべての関数/メソッドの「virtual」キーワードを明示的に記述します。C++11は「override」キーワードを使用します
  • 派生クラスの関数/メソッドが再度サブクラス化されない場合は、キーワード'virtual'にコメントを付けて、関数/メソッドがオーバーライドされたことを示しますが、それを再度オーバーライドするクラスはありません。もちろん、このクラスがfinal(派生不可)にされない限り、派生クラスで誰かがオーバーライドするのを防ぐことはできませんが、メソッドがオーバーライドされることは想定されていないことを示しています。例:/*virtual*/ void guiFocusEvent(); C ++ 11、「オーバーライド」とともに「final」キーワードを使用します。例:void guiFocusEvent() override final;
于 2009-09-03T03:52:47.610 に答える
4

追加virtualしても、いずれにしても大きな影響はありません。私はそれを好む傾向がありますが、それは本当に主観的な問題です. ただし、 Visual C++でoverrideandsealedキーワードを確実に使用すると、コンパイル時にエラーを検出する機能が大幅に向上します。

PCH に次の行を含めます。

#if _MSC_VER >= 1400
#define OVERRIDE override
#define SEALED sealed
#else
#define OVERRIDE
#define SEALED
#endif
于 2009-09-03T01:47:37.607 に答える
3

私は、コンパイラーが省略できる構文を使用しない傾向があります。そうは言っても、C# の設計の一部 (C++ を改善しようとする試み) では、仮想メソッドのオーバーライドを「オーバーライド」とラベル付けする必要があり、それは合理的な考えのようです。私の懸念は、これは完全にオプションであるため、誰かがそれを省略するのは時間の問題であり、それまでにオーバーライドが「仮想」で指定されていることを期待する習慣になってしまうことです。言語の制限内で生活するのが最善かもしれません。

于 2009-09-03T01:38:35.650 に答える
0

1つの欠点が考えられます。クラスメンバー関数がオーバーライドされず、仮想として宣言すると、そのクラス定義の仮想テーブルに不要なエントリが追加されます。

于 2009-09-30T16:20:33.657 に答える
0

注:私の答えは、私たちの何人かがまだ立ち往生しているC ++ 03に関するものです。C++11 には、@JustinTime がコメントで提案しているように、次の提案の代わりにおそらく使用する必要があるoverrideandキーワードがあります。final

すでにたくさんの答えがあり、最も際立っている 2 つの相反する意見があります。@ 280Z28 が彼の回答で言及したことを @StevenSudit の意見と @ Abhay のスタイル ガイドラインと組み合わせたいと思います。

私は @280Z28 に同意しません。Windows でのみそのコードを使用することが確実でない限り、Microsoft の言語拡張機能は使用しません。

でもキーワードは好きです。それでは、明確にするために #define-d キーワードを追加してみませんか?

#define OVERRIDE
#define SEALED

また

#define OVERRIDE virtual
#define SEALED virtual

違いは、3番目のポイントで概説した場合に何をしたいのかについてのあなたの決定です。

3 - 何らかのエラーにより仮想が IFoo から削除された場合でも、すべての子は引き続き機能します (CFooSpecialization::DoBar は、単純に非表示にするのではなく、CFooBase::DoBar をオーバーライドします)。

私はそれがプログラミングエラーであると主張しますが、「修正」はなく、おそらくそれを軽減することさえ気にするべきではありませんが、クラッシュするか、他の方法でプログラマーに通知する必要があります(ただし、1つの正しいことは考えられません今)。

最初のオプションを選択し、#define's を追加したくない場合は、次のようなコメントを使用できます。

/* override */
/* sealed */

そして、それはあなたが明確にしたいすべてのケースで仕事をするはずです.なぜなら、仮想という言葉があなたが望むことに対して十分に明確であるとは考えていないからです.

于 2014-02-17T22:40:13.407 に答える