C ++仮想関数 - 仮想テーブル - 仮想ポインタ - ポリモーフィズム - どのようにポリモーフィズム - 純粋仮想関数 - 抽象クラス

              / - >クラス - >仮想テーブルの作成/

仮想コンストラクタで

             \ - >オブジェクト - >仮想ポインタ\初期化 

クラスの多型:仮想関数と遅延バインディング(実行時)に基づいて実装 

 

1.仮想キーワードで呼び出された関数が宣言された仮想関数を、仮想関数は持っている必要があり、クラスのメンバ関数を

2クラスの仮想関数の存在は、三次元仮想関数テーブルは、呼び出した仮想テーブルをObjectクラスの仮想テーブルは開始へのポインタがある仮想ポインタを仮想テーブルは、クラスに対応し、オブジェクトに対応する仮想テーブルポインタです。
3.多型は、達成するためのインタフェースの様々な、オブジェクト指向のコアです。多型多型は、クラスや関数に分かれています。
4.多型は、動的結合に関連して、仮想関数で実現しました。
5. 純粋仮想関数は = 0一緒に仮想関数です。
純粋仮想関数:仮想ボイド(呼吸)= 0 ; すなわち、抽象クラス!ということです!この機能のサブクラスの派生クラス内のコンテンツの最初の名前ではなく、コンテンツを実装する必要があります!
6. 抽象クラスは、そのクラスには、少なくとも1つの純粋仮想関数を備えています。

我々は例を見て:例1 1-。
の#include <、でiostream.h>
クラス動物
{
パブリック:
       ボイドSLEEP()
       {
              COUT << "動物SLEEP" << ENDL;
       }
       ボイド  ブリーズ()
       {
              COUT <<「動物が呼吸します「<<てendl;
       }
}。

クラスの魚:公共の動物
{
パブリック:
       無効  ()
       {
              coutの<< "魚のバブル" <<てendl;
       }
}。

ボイドメイン()
{
       魚FH。
       動物*パン=&FH; //隐式类型转换
       、汎>呼吸();

}

 

いかなる仮想関数は、実施例1-1の手順で定義されていないことに留意されたいです。例1-1プログラムの実施の結果が何であるかを考えてみましょうか?

答えは出力されます:動物が呼吸します

 

我々 main()関数は、魚のクラスの最初のオブジェクトのFHを定義し、ポインタ変数パン動物を指すのクラスを定義し、FHは、ポインタ変数パンのアドレスを割り当てるし、次いで(可変コール汎>息を使用します)。)魚が(呼吸するクラスを呼び出すべきである、実際には対象魚のクラスで多くの学生がこのような状況になる傾向があり、C ++多型がそのFHを混同し、「魚のバブル」の出力は、結果はそうではありません。理由をお聞かせするには、次の2つの方法。
1、コンパイルの角度
コンパイル時にC ++コンパイラは、各オブジェクトに対して呼び出される関数を決定するために(この機能のために必要なことは非仮想であると呼ばれているアドレス)事前バインディング(事前バインディング)私たちは、クラスの魚オブジェクト、 FHアドレスはパン、割り当てられたときにC ++コンパイラの型変換を、その後、C ++コンパイラは、保存された変数のパンは、対象動物のアドレスであると考えています。行う場合汎>呼吸()メイン()関数が呼び出されると、当然、オブジェクトを呼吸動物の関数です。
2、メモリモデルの角度
以下に示すように、我々は、魚にオブジェクトのメモリモデルを与えます:

仮想機能 - 仮想テーブル - 仮想ポインタ - ポリモーフィズム - どのようにポリモーフィズム - 純粋仮想関数 - 抽象クラス(RPM) -  QiqiのハER〜 -  Qiqiのハ小胞体〜ブログ

図1-1魚メモリモデルクラスオブジェクト
私たちは魚を構築するオブジェクトクラス、動物がいるので、スプライシング、構造のその部分を完了するために、クラスのコンストラクタを呼び出し、その後、魚、オブジェクトクラスの動物を構築するためにファーストクラスのコンストラクタを呼び出し、完全な魚のオブジェクト。我々は、魚のクラスは、動物型に変換されたターゲットと、オブジェクトは、図1-1にある全てのメモリ・モデルの元のオブジェクトの上半分であると考えられている「オブジェクトによって占有動物メモリ。」私たちはそのメソッドを呼び出すためにオブジェクトポインタ型変換を使用するときに、当然のことながら、それがメモリになっているメソッドを呼び出すことです。したがって、動物の出力が呼吸する、先に出てきます。
多くの学生が考えるように、実施例1-1のプログラムでは、我々はパンが実際に魚のオブジェクトクラスを指して知っている、私たちは魚の結果出力は、方法を呼吸していることを、そのメソッド呼び出しは、魚のように息を願っています。今回は、関係のデビューに仮想関数に向けます。

前の出力の結果は、コンパイル時にコンパイラので、我々が使用する必要があります。この問題は解決するために、関数オブジェクトのアドレスをコールすることが決定された遅延バインディング(実行時バインディング)技術を。コンパイラは遅延バインディング使用すると、オブジェクトの正しい型に移動し、関数を呼び出すために、実行時に決定されます。そして、基底クラス内の関数を宣言するときにvirtualキーワードを使用し、コンパイラは遅延バインディング使用してみましょうこの、(それらの多くは、仮想関数を使用すると、多くの間違った例を書いていないので、これが必要であることに注意してください)機能我々は仮想関数を呼び出します。関数が基底クラスの仮想として宣言されると、関数が明示的に仮想として宣言する必要がなく、すべての派生クラスで仮想的です(ただし、後半のコードを検出するために、あなたは、派生クラスでvirtualキーワードを追加する必要があります)

 

例1-1次のコードが変更され、次のように、動物のクラスブリーズ()関数は、仮想宣言される:
実施例2 1-
する#include <、でiostream.h>
クラス動物
{
パブリック:
       ボイドSLEEP()
       {
              COUT <<「動物SLEEP "<< ENDL;
       }
       仮想 ボイド  ブリーズ()
       {
              COUTが<<"動物が呼吸"<< ENDL;
       }
};


クラスFISH:公共動物
{
パブリック:
       ボイド  ブリーズ()
       {
              COUT <<"バブルFISH「<< ENDL ;
       }
};

メインボイド()
{
       FISH FH。
       動物*パン=&FH;
 //暗黙の型変換は、
       PAN->()を吹き込む;
}

私たちはもう一度プログラムを実行することができ、あなたは結果が正しい関数を呼び出しているオブジェクトの種類に応じて、「魚のバブル」であることがわかります。
だから我々は()を呼吸するときに何が起こったのか後ろに、仮想として宣言されていますか?
コンパイル時に、コンパイラは、動物のクラスの仮想関数は、コンパイラクラス(すなわちvtableの)仮想テーブルを作成するごとに仮想関数を含むことを発見した、テーブル、アレイに格納されている一次元アレイであります各仮想関数のアドレス。実施例1-2の手順については、動物や魚のクラスが仮想関数が)(呼吸するので、コンパイラは何の仮想サブクラス機能がなくても(これらの2つのクラスの仮想テーブルを確立する必要がありますが、その親が含まれています以下に示すように)したがって、サブクラスを有し、そこです。

仮想機能 - 仮想テーブル - 仮想ポインタ - ポリモーフィズム - どのようにポリモーフィズム - 純粋仮想関数 - 抽象クラス(RPM) -  QiqiのハER〜 -  Qiqiのハ小胞体〜ブログ

                                                    図1 - 2動物や魚ベースクラスの仮想テーブル


それでは、どのように仮想テーブルにそれを見つけるのですか?コンパイラは、仮想テーブルへのポインタ(すなわちvptr)、各オブジェクト・クラスのオブジェクトのクラスの仮想テーブルへのポインタポイントを提供します。プログラムは、自分のクラスの仮想テーブルvptr正確なポイントは、あなたが仮想関数を呼び出すときように、我々は右の機能を見つけることができるように、vptrを初期化するオブジェクトの種類に応じて、実行されています。実施例1-2の手順については、実際のオブジェクトのでパン型魚ので、クラスの仮想テーブルの魚vptr点を指摘呼び出すとき)(ブリーズ場合、汎>、仮想アドレスの関数は、テーブルクラスの魚に見出されます()関数を呼吸します。


これは、各オブジェクトの仮想関数の呼び出しは、仮想テーブルポインタによってインデックス付けされているため、仮想テーブルポインタの正しい初期化が非常に重要であるかを決定しますです。仮想テーブルポインタが正しく初期化されていない前に、言い換えれば、我々は仮想関数を呼び出すことができません。その後、または任意の場所でいつでも仮想テーブルポインタは、それを初期化?


答えは、コンストラクタで仮想テーブルの仮想テーブルポインタを作成し、初期化することです。最初のコンパイラは親だけが後継者の後にバックがあるかどうかわからない「を参照してください。」その場合、親クラスのコンストラクタを呼び出し、コンストラクタクラスオブジェクトで、順番あなたのコンストラクタを呼び出すことを忘れないでください、それが初期化仮想テーブルに親クラスの仮想テーブルポインタの仮想テーブルポインタ親オブジェクト。サブクラスは、サブクラス仮想テーブルポインタオブジェクトは、仮想テーブルを指し示すように初期化されるとき、コンストラクタが実行されます。魚FHクラスオブジェクトの構築が完了した実施例2-2の手順については、内部仮想テーブルポインタは意志魚のクラスの仮想テーブルを指すように初期化されます。クラスの最後の呼び出しは(魚を呼吸するように変換型後、>汎を呼び出すパン魚は実際にオブジェクトのクラスを指すので、)(呼吸、仮想テーブルポインタ内のオブジェクトは、魚のクラスの仮想テーブルであります)機能。


注:仮想関数呼び出しの場合、各オブジェクト内の仮想テーブルポインタを有し、仮想テーブルポインタは、本クラスの仮想テーブルに初期化されます。そのため、プログラムに関係なく、オブジェクトの種類のC ++実装で多型の原理をある動的オブジェクトの関数呼び出しを、達成するために、あなたはどのように変換するが、オブジェクトの仮想テーブルポインタの内部が固定されているので。
概要(仮想関数を持つ基本クラス):


1.各クラスには、仮想テーブルを持っています。
2.仮想テーブルは、サブクラスが仮想関数をオーバーライドしていない場合は、アドレスのサブクラス仮想テーブルはまだ機能のものであろうが、基底クラスの仮想関数に、このアドレスポイントを達成するために、継承することができます。3つのベース・クラス、仮想関数がある場合、基本クラスの仮想テーブルは、三(仮想関数アドレス)を有する、派生クラスの仮想テーブルを有するであろう、少なくとも三つの、対応する仮想関数オーバーライドする場合、仮想テーブルアドレスは、達成するために、その仮想関数を指して、変更されます。派生クラスは、独自の仮想関数を持っている場合は、仮想テーブルが追加されます。
仮想アドレスのベース・クラス、仮想関数テーブルの同じ配列順序と配列表3.仮想派生クラスの仮想関数のアドレス。
 


これは、C ++の多型です。コンパイル時にC ++コンパイラ、動物クラス()関数を呼吸たC ++遅延バインディング(実行時バインディング)技術を使用される仮想関数です。それが呼び出される機能を確認するために(プログラムでは、私たちの魚道のクラスオブジェクトを扱う)特定の機能は、オブジェクトの種類に応じて、コンパイル時に、しかし、実行時に呼び出しを決定することはありませんが、この能力が呼び出されますC ++多型。私たちは、仮想キーワードの前に追加したとき、コンパイル時にC ++コンパイラが呼び出される関数を決定、それは早期(初期の結合)結合と呼ばれている()関数を呼吸していません。

 

仮想関数が基本クラスで定義され、特定の動作の目的は、その派生クラスが定義されていません。

例:

基本クラスを定義します。クラスの動物//動物。その機能息()//呼吸
2番目のクラスクラス魚//魚を定義します。また、)(呼吸として機能します

そして、クラスclass羊//羊を定義します。また、)(呼吸として機能します

 

派生クラスの基本クラスとして定義されたコード、魚、ヒツジ動物を簡素化します。
しかし、魚や羊の息は1つが、水の中に水を介して直接呼吸空気を呼吸し、同じではありません。基底クラスのみ仮想息定義そのためクラスは、息をする方法を決定するために定義することができる、それは空の仮想関数です。この機能により、サブクラスで定義されています。手順は、一般的に特定され、その後、それは基底クラスの仮想関数の中で発見され、最後の操作は、基底クラスの関数であるその基底クラスを見つけ、それが基底クラスの場合、クラスを見つけ、実行され、それは意志サブクラス機能で同じ名前を見つけるために戻って行きます。派生クラスは、サブクラスと呼ばれています。基本クラスは、また、親クラスとして知られています。これは、多型は、仮想関数、等(呼吸)Aをもたらす反射されます。

多型は、ここでクラス多型を指します。
関数は、関数を参照多型は、多くの異なるパラメータの関数として定義され、彼らは一般的にこの関数を呼び出す際に、異なるパラメータのために、それは同じ名前の別の関数を呼び出しますが、ヘッダファイル内に存在します。例:のRect()//長方形。そのパラメータは、2つの座標点(点、点)とすることができる、4点の座標(X1、Y1、X2、Y2であってもよい ) リロード機能が多型と機能と呼ばれています。

仮想関数と遅延限界を達成するための手段を持つクラスの多型。多型の関数は、関数をオーバーロードされます。

私たちは、ポインタ/参照が関数を呼び出す使用する場合、通常の状況下では、(仮想関数を含まない)、呼び出される関数は、に依存し
、ポインタ/参照の型。ポインタ/参照がオブジェクトポインタ/参照が派生クラスと呼ばれている派生した場合、ポインタ/参照は、基本クラスのオブジェクトポインタ/ベースクラスを基準と呼ばれている場合すなわち、派生クラスは、この方法ではない場合、それは、もちろん、方法これは、適切な方法を見つけるために、基本クラスまでとなります。コンパイル時にこれらの呼び出しは決定されます。

仮想関数と動的バインディングを使用するときに多型を設計しますが、呼び出しは実行時に決定されることはありません、この時間は、コンパイル時に決定された場合。タイプは、別個のポインタ/参照型とはみなされず、ポインタ/参照オブジェクトが仮想関数テーブルへのその仮想オブジェクト・アドレス・ポインタを決定するために、関数呼び出し、関数呼び出しを決定します。

おすすめ

転載: blog.csdn.net/smartgps2008/article/details/90745011