C++多態面接問題まとめ
よくある面接問題をまとめ、資料を調べて浅薄な解析をしました.
1.inliine関数は実虚関数でデジタル化できますか?
いいえ、inline関数にはアドレスがないので、虚函数表に保存できません.
2.静的メンバーは虚関数として使用できますか?
いいえ、静的メンバー関数にはthisポインタがありません.:メンバー関数の甘えは虚関数テーブルにアクセスできません.静的メンバー関数は虚関数テーブルに入れません.
3.コンストラクション関数は虚関数でよいですか?
いいえ、オブジェクト内の虚関数ポインタはオブジェクト構造時に初期化されます.
4.構造関数は虚関数でよいですか?どのシーンの下で構造関数が虚関数ですか?
はい、構造関数を虚関数に設定したほうがいいです.メモリ漏洩の問題を避けることができます.親のポインタが子クラスのオブジェクトを指している場合、子クラスのオブジェクトの虚関数が多態に書かれていない場合、親の構造関数だけを呼び出し、自分の構造関数を呼び出すことはできませんが、オブジェクトを作成するときに構造関数を呼び出します.したがって、サブクラスのコンストラクション関数を使用するには、彼のコンストラクション関数を呼び出す必要があります.そうすれば、解放しなければならないすべてのリソースが解放され、メモリの漏洩がないことを保証することができます.マルチステートの場合は、サブクラスの構造関数を呼び出してから、親クラスの構造関数を呼び出すと、クラスと親クラスのリソースが解放されます.
5.オブジェクトの一般的な関数へのアクセスは速いですか、それとも虚関数が速いですか.
通常のオブジェクトであれば、同じくらい速いです.ポインタオブジェクトまたは参照オブジェクトであれば、マルチステートを構成するため、実行時に虚関数を呼び出すには、まず虚関数数テーブルで検索する必要があります.このようにしてやっと韓国式の住所を手に入れることができて、このように直接関数の住所の普通の関数を手に入れることができるほうが速いです.
6.虚関数テーブルはどの段階で生成されますか.彼はどこに預けていますか.
虚関数の再コンパイル段階で生成され、彼は一般的に再コードセグメント、すなわち定数領域を格納する.
7.次のコードを実行した結果
解析:DeriveはBaseを継承してマルチステートを実現しているのは明らかであるが,x()のみが虚関数書き換えであり,y()はサブクラスに虚関数のみが宣言されており,親クラスでは声名がないためy()は虚関数書き換えではなく親クラスのy()を再定義することができないため,p呼び出しy()のときに直接Baseのy()を呼び出し,Baseのy()でx()を呼び出し,x()はサブクラスにおいて虚関数書き換えを構成するため,サブクラスにおけるx()を呼び出すと,答えがわからなくなる.
8.クラス内のすべてのメンバー関数を虚関数として宣言できますか.なぜですか.
虚関数は、プログラムが実行されている間にアドレス操作によって本当に呼び出す関数を決定し、通常のメンバー関数はコンパイル時に呼び出す関数を決定します.この両者の違いは、効率的に言えば、虚関数の効率は普通のメンバー関数より低い.虚関数はまずオブジェクトの虚標ポインタを通じて虚関数テーブルのアドレスを取得し、それから虚関数テーブルから対応する関数アドレスを見つけ、最後に関数アドレスに基づいて呼び出すが、普通のメンバー関数は直接アドレスを取得して呼び出すことができるからだ.したがって、すべてのメンバー関数を虚関数として宣言する必要はありません.
9.虚関数テーブルポインタがコンパイラによって初期化されるプロセスはどのように理解されますか?
クラスに虚関数が宣言されると、コンパイラはクラスに虚関数テーブルVSにコードセグメントに格納された虚関数テーブルを生成し、虚関数テーブルは実際には虚関数ポインタを格納するポインタ配列であり、コンパイラによって自動的に生成され、維持される.虚表はクラスに属し、特定のオブジェクトに属していません.1つのクラスには虚表が1つ必要です.同じクラスのすべてのオブジェクトは同じ虚表を使用します.虚表を含むクラスの各オブジェクトに虚表ポインタを持たせるために、コンパイラは各オブジェクトのヘッダに虚表を指すポインタを追加します.このポインタの値は自動的にクラスの虚表を指すように設定されます.各virtaul関数の関数ポインタは虚表に保存されます.単一継承の場合、親クラスの虚表を子クラスの虚表に追加してから、子クラスは自分の新しい虚関数ポインタを追加しますが、VSコンパイラでは通常、新しく追加された虚関数ポインタは見えません.コンパイラがわざと隠しています.複数の継承であれば、子クラスに新しく追加された虚関数ポインタは、最初の継承親クラスの虚関数数表に保存されます.
10.多態の分類?
静的にバインドされたマルチステートは,関数の再ロードによって実現される.動的バインドのマルチステートは虚関数によって実現される.
11.抽象クラスと純虚関数を導入する理由
多態特性の使用を容易にするために、多くの場合、ベースクラスからオブジェクトを生成するのは不合理であり、純虚関数はベースクラスで定義されていないため、サブクラスで実現しなければならないことが要求されている.このような純虚関数を含むベースクラスは抽象クラスと呼ばれ、実例化されてはならない.例えば、果物クラスが純虚関数を実現していない場合、彼も抽象クラスである.
12.虚関数と純虚関数の違いは何ですか.
ベースクラスの観点から,クラスに虚関数が宣言された場合,この関数はクラスで実現され,その役割はこの関数が彼のサブクラスで書き換えられ,動的多様性を実現するためである.純粋な虚関数は、インタフェースにすぎず、関数宣言であり、彼のクラスを宣言することで実現されていません.サブクラスでは、ベースクラスの虚関数を書き換えなくてもよいが、ベースクラスの純虚関数を実装する必要がある.虚関数はインタフェースを継承すると同時にベースクラスの実現も継承し,純虚関数はインタフェースの統一性に注目し,完全にサブクラスによって実現される.
13.マルチステートとは?彼は何の役に立つの?
マルチステートはインタフェースの多様な実装であり、マルチステートはオブジェクト向けの3つの特性の1つである.マルチステートは静的マルチステートと動的マルチステートに分けられる.静的マルチステートには関数のリロードと汎用プログラミングが含まれ、プロセスマルチステートはプログラム呼び出し関数であり、コンパイラはどの実行可能なコードブロックを使用するかを決定します.静的マルチステートは、継承メカニズムおよび虚関数によって実現され、派生クラスのベースクラスポインタまたは参照を指すことによって、派生クラスの同名書き換えメンバー関数にアクセスします.堕胎の役割は、異なるサブクラスのオブジェクトを親として見ることであり、異なるサブクラス間の違いを遮断し、共通のコードを書き、共通のプログラミングを行い、需要の絶えず変化に適応することができる.
1.inliine関数は実虚関数でデジタル化できますか?
いいえ、inline関数にはアドレスがないので、虚函数表に保存できません.
2.静的メンバーは虚関数として使用できますか?
いいえ、静的メンバー関数にはthisポインタがありません.:メンバー関数の甘えは虚関数テーブルにアクセスできません.静的メンバー関数は虚関数テーブルに入れません.
3.コンストラクション関数は虚関数でよいですか?
いいえ、オブジェクト内の虚関数ポインタはオブジェクト構造時に初期化されます.
4.構造関数は虚関数でよいですか?どのシーンの下で構造関数が虚関数ですか?
はい、構造関数を虚関数に設定したほうがいいです.メモリ漏洩の問題を避けることができます.親のポインタが子クラスのオブジェクトを指している場合、子クラスのオブジェクトの虚関数が多態に書かれていない場合、親の構造関数だけを呼び出し、自分の構造関数を呼び出すことはできませんが、オブジェクトを作成するときに構造関数を呼び出します.したがって、サブクラスのコンストラクション関数を使用するには、彼のコンストラクション関数を呼び出す必要があります.そうすれば、解放しなければならないすべてのリソースが解放され、メモリの漏洩がないことを保証することができます.マルチステートの場合は、サブクラスの構造関数を呼び出してから、親クラスの構造関数を呼び出すと、クラスと親クラスのリソースが解放されます.
5.オブジェクトの一般的な関数へのアクセスは速いですか、それとも虚関数が速いですか.
通常のオブジェクトであれば、同じくらい速いです.ポインタオブジェクトまたは参照オブジェクトであれば、マルチステートを構成するため、実行時に虚関数を呼び出すには、まず虚関数数テーブルで検索する必要があります.このようにしてやっと韓国式の住所を手に入れることができて、このように直接関数の住所の普通の関数を手に入れることができるほうが速いです.
6.虚関数テーブルはどの段階で生成されますか.彼はどこに預けていますか.
虚関数の再コンパイル段階で生成され、彼は一般的に再コードセグメント、すなわち定数領域を格納する.
7.次のコードを実行した結果
#include
using namespace std;
class Base
{
public:
virtual void x()
{
cout << "Base::x" << endl;
}
void y()
{
x();
cout << "Base::y" << endl;
}
};
class Derive : public Base
{
public:
virtual void x()
{
cout << "Derive::x" << endl;
}
void y()
{
cout << "Derive::y" << endl;
}
};
int main()
{
Base* p = new Derive;
p->y();
return 0;
}
解析:DeriveはBaseを継承してマルチステートを実現しているのは明らかであるが,x()のみが虚関数書き換えであり,y()はサブクラスに虚関数のみが宣言されており,親クラスでは声名がないためy()は虚関数書き換えではなく親クラスのy()を再定義することができないため,p呼び出しy()のときに直接Baseのy()を呼び出し,Baseのy()でx()を呼び出し,x()はサブクラスにおいて虚関数書き換えを構成するため,サブクラスにおけるx()を呼び出すと,答えがわからなくなる.
8.クラス内のすべてのメンバー関数を虚関数として宣言できますか.なぜですか.
虚関数は、プログラムが実行されている間にアドレス操作によって本当に呼び出す関数を決定し、通常のメンバー関数はコンパイル時に呼び出す関数を決定します.この両者の違いは、効率的に言えば、虚関数の効率は普通のメンバー関数より低い.虚関数はまずオブジェクトの虚標ポインタを通じて虚関数テーブルのアドレスを取得し、それから虚関数テーブルから対応する関数アドレスを見つけ、最後に関数アドレスに基づいて呼び出すが、普通のメンバー関数は直接アドレスを取得して呼び出すことができるからだ.したがって、すべてのメンバー関数を虚関数として宣言する必要はありません.
9.虚関数テーブルポインタがコンパイラによって初期化されるプロセスはどのように理解されますか?
クラスに虚関数が宣言されると、コンパイラはクラスに虚関数テーブルVSにコードセグメントに格納された虚関数テーブルを生成し、虚関数テーブルは実際には虚関数ポインタを格納するポインタ配列であり、コンパイラによって自動的に生成され、維持される.虚表はクラスに属し、特定のオブジェクトに属していません.1つのクラスには虚表が1つ必要です.同じクラスのすべてのオブジェクトは同じ虚表を使用します.虚表を含むクラスの各オブジェクトに虚表ポインタを持たせるために、コンパイラは各オブジェクトのヘッダに虚表を指すポインタを追加します.このポインタの値は自動的にクラスの虚表を指すように設定されます.各virtaul関数の関数ポインタは虚表に保存されます.単一継承の場合、親クラスの虚表を子クラスの虚表に追加してから、子クラスは自分の新しい虚関数ポインタを追加しますが、VSコンパイラでは通常、新しく追加された虚関数ポインタは見えません.コンパイラがわざと隠しています.複数の継承であれば、子クラスに新しく追加された虚関数ポインタは、最初の継承親クラスの虚関数数表に保存されます.
10.多態の分類?
静的にバインドされたマルチステートは,関数の再ロードによって実現される.動的バインドのマルチステートは虚関数によって実現される.
11.抽象クラスと純虚関数を導入する理由
多態特性の使用を容易にするために、多くの場合、ベースクラスからオブジェクトを生成するのは不合理であり、純虚関数はベースクラスで定義されていないため、サブクラスで実現しなければならないことが要求されている.このような純虚関数を含むベースクラスは抽象クラスと呼ばれ、実例化されてはならない.例えば、果物クラスが純虚関数を実現していない場合、彼も抽象クラスである.
12.虚関数と純虚関数の違いは何ですか.
ベースクラスの観点から,クラスに虚関数が宣言された場合,この関数はクラスで実現され,その役割はこの関数が彼のサブクラスで書き換えられ,動的多様性を実現するためである.純粋な虚関数は、インタフェースにすぎず、関数宣言であり、彼のクラスを宣言することで実現されていません.サブクラスでは、ベースクラスの虚関数を書き換えなくてもよいが、ベースクラスの純虚関数を実装する必要がある.虚関数はインタフェースを継承すると同時にベースクラスの実現も継承し,純虚関数はインタフェースの統一性に注目し,完全にサブクラスによって実現される.
13.マルチステートとは?彼は何の役に立つの?
マルチステートはインタフェースの多様な実装であり、マルチステートはオブジェクト向けの3つの特性の1つである.マルチステートは静的マルチステートと動的マルチステートに分けられる.静的マルチステートには関数のリロードと汎用プログラミングが含まれ、プロセスマルチステートはプログラム呼び出し関数であり、コンパイラはどの実行可能なコードブロックを使用するかを決定します.静的マルチステートは、継承メカニズムおよび虚関数によって実現され、派生クラスのベースクラスポインタまたは参照を指すことによって、派生クラスの同名書き換えメンバー関数にアクセスします.堕胎の役割は、異なるサブクラスのオブジェクトを親として見ることであり、異なるサブクラス間の違いを遮断し、共通のコードを書き、共通のプログラミングを行い、需要の絶えず変化に適応することができる.