4

仮想関数について読んでいて、

VF は、継承されたクラスのポリモーフィズムで使用されます。

そのため、クラスと派生クラスの両方が同じ関数名を持つ場合、VF は適切な関数を関数呼び出しにバインドします。

つまり、問題の関数が基底クラスで virtual に指定されている場合、派生クラスの関数が呼び出されます。仮想でない場合は、基本クラスの関数が呼び出されます。

Java ではデフォルトで: すべての関数は仮想 C++: 非仮想であり、Java では final のプライベート アクセス修飾子を使用して仮想にすることができますが、C++ では Virtual キーワードを使用して関数を仮想にします。

上記の理論に基づいて、私はコードを書きました:

#include <iostream>

class base{
    public : 
        virtual void function1(){
            std::cout<<"BaseVirtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Base NonVirtual"<<std::endl;
        }
};


class derieved: public base
{
    public : 
        void function1(){
            std::cout<<"Derieved Virtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Derieved NonVirtual"<<std::endl;
        }
};



int main()
{
    base b1;
    derieved d1;

    b1.function1();
    b1.function2();

    d1.function1();
    d1.function2();    

}

事実に基づいて、仮想関数の場合、派生クラス関数のみが呼び出される場合、上記のプログラムの出力は次のようになります。

BaseVirtual
Base NonVirtual
Derieved Virtual
Base NonVirtual

ただし、次のようになりました。

BaseVirtual
Base NonVirtual
Derieved Virtual
Derieved NonVirtual

もちろん、これは正しいに違いありません。したがって、私の質問は、出力がステートメントに完全に違反していることです。問題の関数が基本クラスで仮想に指定されている場合、派生クラスの関数が呼び出されます。仮想でない場合は、基本クラスの関数が呼び出されます。呼び出しの場合:

  d1.function2();    
4

3 に答える 3

9

はい..基本クラスポインタを使用して派生クラスオブジェクトにアクセスしようとしている場合にのみ、仮想の役割が明らかになります。

あなたの例で:-

#include <iostream>

class base{
    public : 
        virtual void function1(){
            std::cout<<"BaseVirtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Base NonVirtual"<<std::endl;
        }
};


class derieved: public base
{
    public : 
        void function1(){
            std::cout<<"Derieved Virtual"<<std::endl;
        }

        void function2(){
            std::cout<<"Derieved NonVirtual"<<std::endl;
        }
};



int main()
{
    base *b1;
    derieved d1;

    b1=&d1;

    b1->function1();
    b1->function2();    
    return 0;
}

出力:-

Derieved Virtual
Base NonVirtual
于 2012-10-23T03:34:54.490 に答える
4

現在、 と のそれぞれに 1 つのオブジェクトを作成baseし、それらのオブジェクトに対してと を直接derived呼び出しています。これらの条件下では、(またはその欠如)はまったく違いはありません。function1function2virtual

少なくとも C++ では、virtual基本クラスまたは派生クラスのいずれかである可能性のあるオブジェクトを参照している基本クラスへのポインター (または参照) を操作する必要があります。

base *b2 = &d1;

// invoke non-virtual function. Inovkes base::function1, because we're using 
// pointer to base.
b2->function1(); 

// invoke virtual function. Invokes derived::function2 because the pointee object
// is a derived.
b2->function2();

これは、(たとえば) オブジェクトへのポインターのコレクションがあり、それらのポインターが参照するオブジェクトがいくつかの異なる型のいずれかである場合に特に便利です。古典的な例の 1 つは、、、 などを派生させた基本shapeクラスです。eachのメンバーを呼び出すと、それぞれが独自の形状を描画します。この特定のケースでは、基本クラスはおそらく抽象基本クラスです。メンバーは「純粋仮想」と宣言されています。つまり、基本クラスのオブジェクトを作成したり、派生クラスのインスタンスを作成したりすることはできません。メンバー関数をオーバーライドするには:linecirclesquaredrawdrawshapedraw

class shape {
public:
    virtual void draw() = 0;
};

class circle : public shape { 
public:
    virtual void draw() { /* draw itself */ }
};

次に、描画プログラムで、ユーザーが作成した形状 (へのポインター) のコレクションを取得します。それらすべてを描画するには、コレクションを調べて、それぞれにそれ自体を描画するように指示します。より高いレベルのコードは、特定の形状が円、正方形、三角形などであるかどうかを知る必要も気にする必要もありません。

for (int i=0; i<shapes.size(); i++)
    shapes[i]->draw();
于 2012-10-23T03:19:34.343 に答える
1

C++ のポリモーフィズムでは、ポインターを利用する必要があります。例を次のように変更した場合:

base *b1 = new base();
base *d1 = new derived();

これは実際に仮想メカニズムを利用します。しかし、あなたはポリモーフィズムの背後にある基本的な考え方と混同しているようです。クラスを派生として定義すると、もちろん、derivedクラスで定義された関数が呼び出されbaseます。

編集:これをより明確にするために、出力と説明を次に示します。

b1->function1(); //Will call base::function1()
b1->function2(); //Will call base::function2()
d1->function1(); //Will call derived::function1()
d2->function2(); //Will call derived::function2()

すべてのポリモーフィズム/仮想呼び出しでは、(正しい) 派生関数を呼び出しながら、派生ポインターを基本型として扱うことができます。したがって、次のような別の機能があるとします。

void foo(base& b)
{
    b.function1();
}

次に、通過b1すると が呼び出さbase::function1()れ、通過d1すると が呼び出されますderived::function1()

于 2012-10-23T03:17:31.900 に答える