47195


c++の仮想関数について勉強していますが以下の二点を教えていただけますでしょうか。？  
新版明解c++中級編の本を読んでいますがつまりどういうことなのかがわからないので質問しました。  
1,仮想関数の利点  
2,仮想関数の使い方

[code]

            #include <iostream>
            #include <string>
            #include "conio.h"
            using namespace std;
    
    
            class A {
    
            public:
    
    
                virtual void f1() {
                    cout <<"A::f1()virtualです"<< endl;
                }
    
                virtual void f2() {
                    cout<<"A::f1()virtualです"<<endl;
                }
            };
    
            class B :public  A {
    
            public:
    
                void f1() {
                    cout << "B::f1()\n";
                }
    
            };
    
    
    
    
    
    
    
            int main() {
    
                B b;
                b.f1();
    
    
    
                _getch();
                return 0;
            }
    
[/code]


CC BY-SA 4.0
2018-08-02T23:19:32.807
47194
2018-08-03T02:01:23.060
question
c++
c++ 仮想関数の利点について


そのサンプルで `virtual` を理解できたら大したものというか、たぶん見ているサンプルは説明途中のものでもっと続きがあるはずというか。

`virtual` については下記質疑応答でだいたい説明できていると個人的には思います。  
[c++ 継承クラスを理解したい](https://ja.stackoverflow.com/questions/44708/)

  * 基底クラスを作るのは A 氏
  * それを派生させて使うのは B 氏や C 氏など複数いて事前に予測不能
  * A 氏の作ったライブラリ中から `virtual` な関数を呼ぶと、実際に呼ばれるのは B 氏の実装した関数だったり C 氏の実装した関数だったりする
  * `virtual` を使わないと A 氏の実装した関数が呼ばれるだけで誰もうれしくない

ってあたりで。

「真に呼びたい関数」を探す手間がかかる分だけ `virtual` 関数は非 `virtual`
な関数より実行時間がかかるのですが、そのデメリットより便利さが勝つ場合に使います。

* * *

サンプル書いてみました。たぶんこれより短く書くのは困難。

[code]

    #include <iostream>
    
    struct b {
        virtual ~b() { }
        virtual void f1() { std::cout << "b::f1\n"; }
        /*virtual*/ void f2() { std::cout << "b::f2\n"; }
    };
    
    struct d1 : b {
        virtual void f1() { std::cout << "d1::f1\n"; }
        /*virtual*/ void f2() { std::cout << "d1::f2\n"; }
    };
    
    int main() {
        d1 d;
        d.f1();
        d.f2();
        b* p=&d;
        p->f1();
        p->f2();
    }
    
[/code]

実行する前に結果を予測してください。

* * *

質問に対する答えとしては Q1 Q2 とも下記説明で言い尽くされていて

「派生クラスインスタンスへのポインタ右辺値は、基底クラスへのポインタ変数で保持できる」ってのが理解できている前提で

基底クラスへのポインタ変数からオーバーライドされているメンバー関数呼び出しをする際

  * `virtual` でない関数の場合、基底クラスのメンバー関数が呼ばれる
  * `virtual` な関数の場合、派生クラスのメンバー関数が呼ばれる

とそれだけです。それだけのことなんですが、これが継承派生関係における最大のメリットです。

* * *

応用問題１．  
- `struct d2 : b` を適切に実装し、同様に `d2` インスタンスへの `b` ポインタ経由で `f1()` を呼ぶコードを書いてみよ  
- 実行する前に挙動を予測せよ

応用問題２．  
- `struct d3 : d1` を適切に実装し、同様に `d3` インスタンスへの `b` ポインタ経由で `f1()` を呼ぶコードを書いてみよ  
- 実行する前に挙動を予測せよ


CC BY-SA 4.0
2018-08-02T23:54:33.467
47195
2018-08-03T02:01:23.060
2018-08-03T02:01:23.060
8589
8589
47194
answer