マルチステート原則

免責事項:この記事はブロガーオリジナル記事です、続くBY-SAのCC 4.0を著作権契約、複製、元のソースのリンクと、この文を添付してください。
このリンク: https://blog.csdn.net/dxd_123456/article/details/78125048

1、多状態の原則
私たちは3つの多型の実装条件を知っている:1.継承、仮想関数は2を上書きし、親クラスに3つのポインタまたは参照がオブジェクトをサブクラス。
クラスの関数がある場合、仮想関数ますです仮想関数テーブルへのクラスの増加仮想関数ポインタ、仮想関数ポインタは、仮想関数テーブルは、関数ポインタストレージクラスメンバのデータ構造であり、仮想関数テーブルが自動的にコンパイラおよび保守によって生成され、仮想メンバ関数仮想関数テーブルにコンパイラによって配置され、仮想関数が存在する、各オブジェクトが仮想関数テーブルへのポインタ(vptr)を有しています

void func(){}
virtual void func ()  // print (A * const this)
调用:p->func();  // p->vfptr->func()

仮想関数呼び出しプロセス
とお電話の際は最終的に、コンパイラがいるかどうかfuncを適切な仮想関数に従って解釈されます:それは仮想関数ではない場合1.:直接メンバ関数を決定することができ、コンパイラが呼び出された(とも呼ばれる静的バインディング)仮想関数である場合2.:オブジェクトへのvtableポインタpおよびコールによって指さVPTR関数funcを見つけるために、コンパイラは、ポインタでフェッチすると言うことができる(また、動的な結合又は接着が後とも呼ばれます)ブロックアドレス上の仮想関数ポインタは、vtableの仮想関数ポインタは、同じ名前の関数でフェッチ
注:仮想関数テーブルポインタVPTR機能は、プログラムで実行されるコール書き換えることにより、によって実際のアドレス動作を決定する必要があります関数が呼び出されるべきである、とコンパイラが呼び出すために誰が判断した場合、通常のメンバ関数があるので、仮想関数の効率ははるかに低いので、それはより良い仮想関数ではありません。C ++コンパイラを実行機能を実行する、オブジェクトを区別する必要がないサブクラスまたは親クラス・オブジェクトであります

2、コンストラクタは達成することができます仮想関数を呼び出し
、その後、サブクラスのコンストラクタ、シーケンシャル建設は、親クラスを構築することで
、親vfptr仮想関数テーブルに、仮想関数ポインタポイントを親クラスのコンストラクタ関数を呼び出した時
とき、親クラスのコンストラクタの終了、コンストラクタサブクラスを呼び出すとき、サブクラスvfptr仮想関数テーブルへの仮想関数ポインタが
結論:コンストラクタ多型不可能

class A
{
public:
    A()
    {
        // 在构造函数中调用虚函数是不能实现多态的
        // 虚函数指针 是分步初始化,一开始指向父类的虚函数表,父类初始化完了以后 指向自己的虚函数表
        print();
    }

    virtual void print()
    {
        printf ("AAAAAAAAAAAAAAAAAAAAA\n");
    }
public:
    int a;
};

3にサブクラスアレイポインタで親クラスを指していない
ポインタはデータ型であり、クラスオブジェクトp ++ / C ++へのポインタ-は、まだ利用可能です。
ポインタ演算は、ポインタの種類に応じて行われます。
P ++異なるステップのP ++親クラスとサブクラス、混合しないように、親クラスのポインタ++配列オブジェクトのサブクラスの方法を使用していない
以下の場合を見ることができます。

class A
{
public:
    A(int a)
    {
        this->a = a;
    }

    virtual void print()
    {
        printf ("a = %d\n", a);
    }
public:
    int a;
};
class B:public A
{
public:
    B(int a, int b): A(a)
    {
        this->b = b;
    }

    virtual void print()
    {
        printf ("a = %d, b = %d\n",a, b);
    }

public:
    int b;
};


int main()
{
    B b[5] = {B(1,2), B(3,4), B(5,6), B(7,8), B(9,10)};

    B *pb = b;

    A *pa = b;

    // 一般来讲  基类 和 派生类 的指针步长是不一样的, 除非派生类没有增加任何成员
    // pa + 1 =  pa + sizeof(A)   pb + 1 = pb + sizeof(B)
    // 不要基类的指针 操作派生类的数组
    for (int i = 0; i < 5; i++)
    {
        // pb[i].print();

        // pa[i] ==> pa + i ==> (int)pa + sizeof(A) ==> (int)pa + 8
        // sizeof(B)  =  12
        pa[i].print(); 


        // long * p = 0x100000  ==> p + 1 = 0x10004  ==>  (long)p + 1 = 0x10001
    }

    return 0;
}

おすすめ

転載: blog.csdn.net/dxd_123456/article/details/78125048