9

私が取り組んでいるいくつかのコードを見つけたので、最適な設計実装は何かと考えていました。

基本クラスがメソッドを仮想として定義しているが、空の本体も実装しているため、派生クラスが本体を実装する必要がない場合、代わりに純粋にするべきではありませんか?

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3
  1. 現在のコード。
  2. アイデア 1: この派生オブジェクトがこのメソッド本体を実装していないことをユーザーに警告します。
  3. アイデア 2: 派生クラスに、空であろうとなかろうと、本体を実装するように強制します。

信頼できる素晴らしい SO の人々はどう思いますか?


Edit1:投稿(および回答を読んだ後)後、アサートが悪いことに気付きました!

virtual void AMethod3() = {throw (ENotImplemented)};               // 4
4

10 に答える 10

9

それは、コーディング スタイルがどの程度「純粋」であるかによって少し異なります。一部の人々は、常に純粋仮想関数のみを使用してインターフェイスを定義し、そこからすべての具体的なクラスを派生させる必要があると考えています。

他の人はより実用的で、適切なデフォルトの実装があれば、それを基本クラスに追加できると信じています (オプション 1)。

2 番目のオプションは、実行時まで検出を遅らせるため、あまり役に立たないようです。ほとんどのプログラマーは、オプション 3 のコンパイル エラーを好むでしょう。

いつものように、C++ はいくつかのパラダイムをサポートしており、好みのパラダイムを選択できます。

于 2011-07-27T11:11:20.373 に答える
6

派生クラスがこのメソッドを実装する必要がある場合は、オプション 3 を使用する必要があります。派生クラスでの実装がオプションの場合は、オプション 1 を使用します。オプション 2 は完全に避けてください。

于 2011-07-27T11:06:51.273 に答える
3

基本クラスがメソッドを仮想として定義しているが、空の本体も実装しているため、派生クラスが本体を実装する必要がない場合、代わりに純粋にするべきではありませんか?

それは、派生クラスにメソッドをオーバーライドさせるかどうかによって異なります。その場合は、純粋なvirtual;を使用してください。まさにその要件に対応する言語サポートです。のデフォルトの実装が存在するか、後で存在する可能性がある場合は、実装でamethod純粋なvirtualメソッドを使用します。

class Foo {
    virtual void amethod() = 0;
};

void Foo::amethod() {
    // whatever
}

関数はまだ純粋virtualであるため、Fooクラスをインスタンス化することはできませんが、派生クラスは実装を継承し、そのメソッドはそれを として呼び出すことができますFoo::amethod

于 2011-07-27T11:07:13.223 に答える
2
  • virtual void AMethod1() = 0;: 純粋な仮想は、基本クラスに提供する実装がなく、この動作を実装する必要がある場合最適です。(これはあなたの質問のオプション3です)

  • virtual void AMethod1() {}: 空の実装を持つ仮想は、基本クラスに提供する実装がなく、この動作が実装される可能性がある場合最適です。(これはあなたの質問のオプション1です)

  • virtual void AMethod1() { assert(false); }: 私の意見では、仮想はassert(false)避ける必要があります。有効な用途が見当たりません。その背後にある理論的根拠は、すべてのユースケースが上記の 2 つのオプションでカバーされるということです。動作が実装されているか、実装されている必要があるため、常に失敗する呼び出し可能なメソッドを定義する必要はありません。コンパイラは、この呼び出しを防止することでこれを処理できるため、このオプションを使用すると、このチェックが実行時に延期されるため、リスクが生じます。(これはあなたの質問のオプション2です)

于 2011-07-27T11:23:11.257 に答える
2

メソッドを純粋仮想にすることは、 assertを使用してデフォルトの実装を作成するよりも直感的です。ほとんどの場合、何もしないのがデフォルトの実装である場合、現在のコードの方が優れています。もちろん、ポリモーフィズムを使用する場合は仮想のままにする必要があります。

于 2011-07-27T11:11:44.103 に答える
2

クラスをインスタンス化する必要があるこのような例をかなり見てきました。そのためvirtual、空のボディで使用します。

virtual void AMethod1() {}                 // 1

派生クラスに強制的にこの関数をオーバーライドさせたい場合に、これを使用します。デフォルトは必要ありません。

virtual void AMethod3() = 0;               // 3

したがって、それは本当にあなたが何をしたいかによって異なります。

于 2011-07-27T11:16:14.727 に答える
1

virtualメカニズムが必要なので。以下は私の短い答えです:

(1)virtual void AMethod1() {}

要件:

- Allow creating objects of base class
- Base `virtual` method is use.

(2) virtual void AMethod2() {assert(false);}

要件:

- Allow creating objects of base class
- Base method is not used
- Force derived classes to implement the method (hard way, because it happens at runtime).

(3) virtual void AMethod3() = 0;

要件:

- Don't allow base class object creation
- Force derived classes to implement the method at compile time
于 2011-07-27T11:11:11.573 に答える
1

クラスをインスタンス化するのではなく、それから派生するすべてのクラスの基本クラスとして機能させる場合は、純粋仮想関数を使用する必要があります。

純粋仮想関数について注意すべき重要な点は、これらの関数をすべての派生クラスでオーバーライドする必要があるということです。そうしないと、コンパイルでエラーが発生します。

簡単な例:

class alpha     {
     public:virtual void show()=0; //pure virtual function
    };

class beta : public alpha {

     public:void show()   //overriding
        {
         cout<<"OOP in C++";
        }
    };
void main() {
     alpha *p;
     beta b;
     p=&b;
     p->show();
   }
于 2011-07-27T11:06:29.103 に答える
1

基本クラスがメソッドを仮想として定義しているが、空の本体も実装しているため、派生クラスが本体を実装する必要がない場合、代わりに純粋にするべきではありませんか?

それはあなたのデザインに依存します。メソッドが純粋な仮想の場合、派生クラスの開発者に「クラスを機能させるには、ここに実際のコードを配置する必要があります」というメッセージを送信します。一方、メソッドが空のボディを持つ仮想メソッドである場合、メッセージは「ここにコードを配置してもかまいませんが、実際のニーズ次第です」です。

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3

派生クラスが仮想メソッドを実装していない場合、実行時エラーではなくコンパイル エラーが発生します。

于 2011-07-27T11:21:14.463 に答える
0

単純なルールはありません:

関数が呼び出された場合に一部の派生クラスが何もしないことが理にかなっている場合は、1 (空の実装) を使用します。

派生クラスが関数を実装しないことが意味をなさない場合は、3 を使用します。

関数の前提条件が、別の仮想関数 ha が true を返すことであり、その関数が false (またはそれらの行に沿った何か) を返すデフォルトの実装を持っているというまれなケースでは、2 を使用します。基本的に、インターフェースの一部がオプションの場合。(しかし、通常、このような場合はインターフェイスを派生させる方が適切です。拡張インターフェイスを実装するクラスはそれから派生し、クライアントはそれ dynamic_castを拡張インターフェイスに使用したいと考えています。)

経験上 (ただし、プログラミング スタイルは異なる場合があります)、1 は少なくとも 90% の確率で適用されるようです。20 年以上の C++ の経験で、3 は 1 回か 2 回使用したと思います。

于 2011-07-27T12:56:03.850 に答える