派生クラスのアドレスを基底クラス ポインターに割り当てます。つまり、基底クラス ポインターは派生クラス オブジェクトを参照します。これを通常ポリモーフィズムと呼びます。
ただし、その逆の場合は、コンパイルが成功する前に強制的な型変換が必要になります。
リーリー
どの仮想関数を呼び出すかは、オブジェクトが指す仮想関数テーブルによって決まります。 new Base() を使用すると、pb が指す仮想関数テーブル内の仮想関数が (Derived*) で強制変換されます。変更しない 変更しないでください。非仮想関数は主にポインター型に基づいています。つまり、pd は最初から Derived であるため、Derived 関数を使用すると、メンバー関数は呼び出し時に実際にこのポインターを呼び出します。
virtual 指定子は、非静的メンバー関数が仮想であることを指定し、動的バインディングをサポートします。これは、非静的メンバー関数の最初の宣言の decl-specifier-seq でのみ使用できます (つまり、クラス定義)。 仮想関数は、派生クラスで動作をオーバーライドできるメンバー関数です。
virtual 指定子は、非静的メンバー関数が仮想であることを指定し、動的バインディングをサポートします。これは、非静的メンバー関数の最初の宣言の decl-specifier-seq でのみ使用できます (つまり、クラス定義)。
仮想関数は、派生クラスで動作をオーバーライドできるメンバー関数です。
virtual を使用するということは、この関数がサブクラスによってオーバーライドされる可能性があることを意味し、その結果、サブクラスを指す親クラス ポインターは、ポインター自体のカテゴリに従ってこの関数を呼び出さず、(仮想関数テーブル V-Table を確認することにより)サブクラスによってオーバーライドされた後の関数は function と呼ばれます。 言及する価値があります
このような書き方は正しくありません。少なくとも、親クラスのオブジェクトを指す親クラスのポインタをサブクラスのポインタに割り当てるべきではありません。
ここでの pd->print は、仮想関数テーブル内の親クラスの print を指しているため、
呼び出しは Base::print です
次へ
これは、親クラスのオブジェクトでサブクラスの関数を強制的に呼び出すことです (または、親クラスのオブジェクトを this として使用し、仮想関数テーブルでサブクラスの print を強制的に呼び出します)。これは一般的に推奨されません。
これは実際に実行したばかりですが、理解するのが非常に困難です。
正しいかどうかはわかりませんが、私の考えをお話します。
最初のケースでは、virtual と書かれています。メンバー関数が virtual に追加された場合、呼び出された関数のアドレスは実行中にのみ検出されることを意味します。しかし、どこで見つければいいのでしょうか?各オブジェクトのメモリには仮想テーブルがあるようです (各クラスにはオブジェクトによって共有される仮想テーブルがあるとも言われています)。Derived ポインタが Base オブジェクトのメモリを指しているため、システムは次のようになります。メモリの仮想テーブル内の print 関数のアドレスは、Base クラスの print 関数のアドレスであるため、基本クラスの print 関数は次のようになります。呼ばれました
2 番目のケース: virtual が使用される場合、関数のアドレスはコンパイル中に決定されます。コンパイル時に関数アドレスを決定する方法: ソース プログラムのシンボル テーブルを検索することによって取得されます。次に、メイン プログラムの pd->print() は、明らかに、pd は派生クラスであり、pd->print() は Derived::print と同等です。その場合、コンパイラは派生クラスでそれを検索するため、pdコンパイル時に使用される -> print() 内の print() のアドレスが Derived::print のアドレスに置き換えられるため、サブクラスの print 関数が呼び出されます。
私の言っていることが理解できるか分かりません
どの仮想関数を呼び出すかは、オブジェクトが指す仮想関数テーブルによって決まります。 new Base() を使用すると、pb が指す仮想関数テーブル内の仮想関数が (Derived*) で強制変換されます。変更しない 変更しないでください。非仮想関数は主にポインター型に基づいています。つまり、pd は最初から Derived であるため、Derived 関数を使用すると、メンバー関数は呼び出し時に実際にこのポインターを呼び出します。
virtual を使用するということは、この関数がサブクラスによってオーバーライドされる可能性があることを意味し、その結果、サブクラスを指す親クラス ポインターは、ポインター自体のカテゴリに従ってこの関数を呼び出さず、(仮想関数テーブル V-Table を確認することにより)サブクラスによってオーバーライドされた後の関数は function と呼ばれます。
リーリー言及する価値があります
このような書き方は正しくありません。少なくとも、親クラスのオブジェクトを指す親クラスのポインタをサブクラスのポインタに割り当てるべきではありません。
ここでの pd->print は、仮想関数テーブル内の親クラスの print を指しているため、
リーリー呼び出しは Base::print です
次へ
リーリーこれは、親クラスのオブジェクトでサブクラスの関数を強制的に呼び出すことです (または、親クラスのオブジェクトを this として使用し、仮想関数テーブルでサブクラスの print を強制的に呼び出します)。これは一般的に推奨されません。
これは実際に実行したばかりですが、理解するのが非常に困難です。
正しいかどうかはわかりませんが、私の考えをお話します。
最初のケースでは、virtual と書かれています。メンバー関数が virtual に追加された場合、呼び出された関数のアドレスは実行中にのみ検出されることを意味します。しかし、どこで見つければいいのでしょうか?各オブジェクトのメモリには仮想テーブルがあるようです (各クラスにはオブジェクトによって共有される仮想テーブルがあるとも言われています)。Derived ポインタが Base オブジェクトのメモリを指しているため、システムは次のようになります。メモリの仮想テーブル内の print 関数のアドレスは、Base クラスの print 関数のアドレスであるため、基本クラスの print 関数は次のようになります。呼ばれました
2 番目のケース: virtual が使用される場合、関数のアドレスはコンパイル中に決定されます。コンパイル時に関数アドレスを決定する方法: ソース プログラムのシンボル テーブルを検索することによって取得されます。次に、メイン プログラムの pd->print() は、明らかに、pd は派生クラスであり、pd->print() は Derived::print と同等です。その場合、コンパイラは派生クラスでそれを検索するため、pdコンパイル時に使用される -> print() 内の print() のアドレスが Derived::print のアドレスに置き換えられるため、サブクラスの print 関数が呼び出されます。
私の言っていることが理解できるか分かりません