MOOC C ++ノート(VI):多型

ポリモーフィズム

仮想関数

クラスの定義では、メンバ関数の前に仮想関数virtualキーワードです。
関数宣言で、クラス定義でのみ仮想キーワード、関数本体を書いていません。
コンストラクタと静的メンバ関数は仮想にすることはできません。

多形形態

派生クラスの基底クラスポインタ

ポインタ派生クラスは、ベースクラスのポインタに割り当てることができます。
ベースポインタが同じ名前は、基本クラスと派生クラスの仮想関数を呼び出すとき:
オブジェクトは基本クラスへのポインタ(1)である場合、それは、基本クラスの仮想関数と呼ばれます。
(2)派生クラスのオブジェクトへのポインタ場合は、派生クラスの仮想関数と呼ばれています。
このメカニズムは「多型」と呼ばれています。

    class CBase
    {
    public:
        virtual void SomeVirtualFunction(){}
    };
    class CDerived :public CBase
    {
    public:
        virtual void SomeVirtualFunction() {}
    };
    int main()
    {
        CDerived ODerived;
        CBase*p = &ODerived;
        p->SomeVirtualFunction();//调用哪个函数取决于p指向哪个类的对象。
        return 0;
    }

基底クラスの派生クラスのオブジェクト参照

派生クラスのオブジェクトが参照されるベースクラスに割り当てることができる
ベースクラスで同じ名前の基底クラスと派生クラスの仮想関数呼び出しを参照する場合:
オブジェクトが参照することにより、ベースクラスを参照している場合(1)、ベース・クラス、仮想呼ばれ機能。
参照は、派生クラスのオブジェクトの参照がある場合(2)、それは、派生クラスの仮想関数と呼ばれています。
このメカニズムはまた、「多型」と呼ばれています。

    class CBase
    {
    public:
        virtual void SomeVirtualFunction(){}
    };
    class CDerived :public CBase
    {
    public:
        virtual void SomeVirtualFunction() {}
    };
    int main()
    {
        CDerived ODerived;
        CBase&r = ODerived;
        r.SomeVirtualFunction();//调用哪个函数取决于r引用哪种类型的对象。
        return 0;
    }

非コンストラクタとデストラクタ非仮想関数呼び出し

    class Base
    {
    public:
        void fun1() { this->fun2; }
        virtual void fun2() { cout << "Base::fun2()" << endl; }
    };
    class Derived :public Base
    {
    public:
        virtual void fun2() { cout << "Derived::fun2()" << endl; }
    };
    int main()
    {
        Derived d;
        Base*pBase = &d;
        pBase->fun1();//输出Derived::fun2(),调用哪一个fun2,取决于指向的对象类型。
        return 0;
    }

非仮想関数でオブジェクトの種類に依存するコンストラクタとデストラクタ非仮想関数が呼び出されるコールに指摘又はオブジェクトのタイプによって参照されます。
注意:仮想関数が多型デストラクタとコンストラクタではありません呼び出します。コンパイル時に決定することができ、関数呼び出しは、実行時間が自分または派生クラスの呼び出しをすることを決めたまで待っていない、そのクラスまたは基底クラス定義の関数です。
さらに、機能と同じ基本クラスへ導出されたパラメータのその多形体を確実にするために、仮想の派生クラスが宣言することはできないが、ベースクラスは、次いで多型達成するために使用されている場合、仮想宣言を使用しなければなりません。

原則多型

動的なキーと呼ばれる----コンパイル時または派生クラスで基本クラスで、ランタイムが決定し、最終的に不確実性の仮想関数呼び出しを呼び出して、基本クラスのポインタまたは参照である「動的バインディング。」

Vtable

仮想関数(仮想関数または派生クラス)が仮想関数テーブルを持つ各クラスには、任意のオブジェクト・クラス、仮想関数テーブルポインタに配置されています。仮想関数テーブルには、クラスの仮想関数のアドレスが表示されます。
各クラスは、仮想関数は、これらの余分なバイト(通常、クラス配置ヘッダー空間に格納されている)仮想関数テーブルのアドレスを入れるために使用される(機械語に応じて)、余分な4バイト有します。
関数呼び出し文の多型がアドレスのvtableに基づいて、仮想関数テーブル内の仮想関数アドレスを見て一連にコンパイルすることは、基本クラスのポインタのポイント(または基本クラス参照に引用)に格納され、仮想関数呼び出しオブジェクト指示。
マルチ状態がある程度の時間と空間上の余分なオーバーヘッドを支払う必要があります。

仮想関数テーブル関数の仮想アドレスを変更することによって変化多型に向けたとき(多形性の原理を理解するために)

    #include<iostream>
    using namespace std;
    class A
    {
    public:
        virtual void Func() { cout <<"A::Func" << endl; }
    };

    class B:public A
    {
    public:
        virtual void Func() { cout << "B::Func" << endl; }
    };

    int main(void)
    {
        A a;
        A*pa = new B;
        pa->Func();
        //64位程序指针为8字节
        long long *p1 = (long long*)&a;
        long long *p2 = (long long *)pa;
        *p2 = *p1;
        pa->Func();
        system("pause");
    }

出力は:
B ::のFunc
A ::のFunc
本明細書で第二のFuncは、我々は、仮想関数テーブルポインタがオブジェクトのアドレスを変更するのみ使用するのでAのFuncを呼び出すあります。

仮想デストラクタ

次いで、ベースクラスのデストラクタを呼び出し、ポインタベースクラスを介して誘導されたオブジェクトを削除する際に通常は基底クラスのデストラクタを呼び出し、そのオブジェクトは、派生クラスを削除され、デストラクタ派生クラスを呼び出す必要があります。
:溶液は、仮想基本クラス宣言のデストラクタである
デストラクタ仮想派生クラスが宣言することができない
基本クラスを削除するデストラクタポインタ派生クラスによって、その後ベースクラスデストラクタを呼び出します。
一般的に、クラスの仮想関数の定義の場合、デストラクタは仮想関数として定義されます。代替的に、クラスは、ベースクラスとして使用するには、仮想関数デストラクタとして定義されるべきです。

抽象クラスと純粋仮想関数

純粋仮想関数

特に言葉遣いのための仮想関数の機能なし本体ません、virtual void Fun()=0

抽象クラス

純粋仮想関数を含むことは抽象クラスと呼ばれています。
抽象クラスはまた、抽象クラスのオブジェクトを作成することはできません、新しいクラスの使用を導き出すための基本クラスとして機能することができます。
オブジェクトへの抽象クラスのポインタと参照は、抽象クラスのクラスから派生することができます。(あなたは、抽象クラスのポインタと参照を定義することができますが、エンティティクラスを作成することはできません)。
メンバ関数に抽象クラスは、純粋仮想関数を呼び出すことができるが、デストラクタとコンストラクタが多型ではないので(コンストラクタまたはデストラクタ内の純粋仮想関数を呼び出すことができず、それ自体が純粋仮想空コールこの関数は)無意味です。
抽象から派生したクラスが派生した場合、それは、基本クラスのすべての純粋仮想関数を実装している場合のみ、そして、それは非抽象クラスになることができます。

多型の違い、オーバーロードとカバー

ブログを参照してください:ポリモーフィズム、オーバーロードを、差異および接続をカバー

ポリモーフィックな役割

抽象の抽象状態でオブジェクト指向の設計では、スケーラビリティ、すなわち、より少ない必要が変更する場合、プログラムの機能を変更または増加させるために、コードの増加を向上させることができます。

おすすめ

転載: www.cnblogs.com/z-y-k/p/11618419.html