C++(デフォルトテンプレート、特化テンプレート)をアセンブリの目で見る
【声明:著作権所有、転載歓迎、商業用途に使用しないでください.連絡ポスト:[email protected]】
デフォルト関数はC++の基本的な特徴です.デフォルト関数の定義は簡単です.つまり、関数の入力パラメータまたはいくつかの入力パラメータについて、特定の数値がなければ、デフォルトのデータで置き換えます.呼び出し中に自分のデータを使用すると、デフォルトのデータは私たちが定義したデータで上書きされます.デフォルトの関数の例を次に示します.
上のデフォルトテンプレートの構造がわかりました.次に、特化テンプレートについてお話しします.特化テンプレートとはどういう意味ですか?実は複雑ではありません.テンプレートクラスが汎用テンプレートである以上、その中のデータ型は任意のデータ型であってもよいので、しかし、いくつかのデータ型は避けられない.(ポインタなど)では、いくつかの操作を細かく修正する必要がありますが、これらの小さな修正は元のテンプレート定義ではできません.では、どうすればいいですか.テンプレートクラス定義の名前と一致する形式を再定義するしかありませんが、形式には少し違いがあります.テストを作成してみましょう.
最初の変数の実際の入力関数は次のとおりです.
思考問題:
(1)テンプレートクラスの最初のtypeはデフォルトでよろしいですか?なぜそう考えるのですか?
(2)次のコードはvc 6.0とvc 2005でコンパイルできますか?なぜですか?私たちの設計コードについてどう思いますか?(互換性の面から考えることをお勧めします)
【予告:次の2つのブログはとても面白いです.再帰テンプレートとテンプレートのテンプレートの内容を紹介します】
デフォルト関数はC++の基本的な特徴です.デフォルト関数の定義は簡単です.つまり、関数の入力パラメータまたはいくつかの入力パラメータについて、特定の数値がなければ、デフォルトのデータで置き換えます.呼び出し中に自分のデータを使用すると、デフォルトのデータは私たちが定義したデータで上書きされます.デフォルトの関数の例を次に示します.
int add(int m, int n = 10)
{
return m + n;
}
もし呼び出されたら、どんな違いがありますか?262: int p = add(2);
00401488 push 0Ah
0040148A push 2
0040148C call @ILT+15(add) (00401014)
00401491 add esp,8
00401494 mov dword ptr [ebp-4],eax
263: p = add(3, 4);
00401497 push 4
00401499 push 3
0040149B call @ILT+15(add) (00401014)
004014A0 add esp,8
004014A3 mov dword ptr [ebp-4],eax
上のコードから、データ2が単独で入力されると、コンパイラはデフォルトで10を入力します.もし負けたデータが3、4だったら、コンパイラはデフォルトのデータ10の代わりに4を使います.だから、コンパイラは私たちに中間の置換と判断の仕事をしてくれました.では、今日議論したデフォルトのテンプレートタイプに戻ると、どのような状況になりますか?例を作成できます.template <typename type1, typename type2 = int>
class data
{
type2 value;
public:
data(type2 m): value(m) {}
~data() {}
};
では、2番目のパラメータでデフォルトタイプintを使用していることがわかりますが、デフォルトタイプが使用できることをどのように証明しますか?次のテスト例を設計しました.239: data<int, int> m(2);
004013BD push 2
004013BF lea ecx,[ebp-10h]
004013C2 call @ILT+5(data<int,int>::data<int,int>) (0040100a)
004013C7 mov dword ptr [ebp-4],0
240: data<int> n(3);
004013CE push 3
004013D0 lea ecx,[ebp-14h]
004013D3 call @ILT+5(data<int,int>::data<int,int>) (0040100a)
上のコードは、2つの一時変数を定義し、そのうち1つ目はmであり、入力タイプはintである.2番目の一時変数はnで、入力タイプはintとintです.デフォルトタイプがintであると前述したように、第1の一時変数mと第2の一時変数nの構造関数アドレスは同じであるべきである.では、実際に両者の構造関数は同じではないでしょうか.両者の関数アドレスを見ると,1つは0 x 00410 aであり,もう1つも0 x 00410 aであることが分かった.例は私たちの判断が正しいことを証明した.上のデフォルトテンプレートの構造がわかりました.次に、特化テンプレートについてお話しします.特化テンプレートとはどういう意味ですか?実は複雑ではありません.テンプレートクラスが汎用テンプレートである以上、その中のデータ型は任意のデータ型であってもよいので、しかし、いくつかのデータ型は避けられない.(ポインタなど)では、いくつかの操作を細かく修正する必要がありますが、これらの小さな修正は元のテンプレート定義ではできません.では、どうすればいいですか.テンプレートクラス定義の名前と一致する形式を再定義するしかありませんが、形式には少し違いがあります.テストを作成してみましょう.
template <typename type>
class data
{
public:
data() {printf("normal!
");}
~data() {printf("~normal!
");}
};
template <>
class data<int*>
{
public:
data() {printf("point!
");}
~data() {printf("point!
");}
};
のコードは、2つのクラステンプレートを定義します.しかし、両者の名前は同じであり、この2つのクラス定義の内容が実際には大きな類似性を持っていることを示している.1つ目の定義は標準テンプレートクラスの定義で、2つ目は少し複雑で、デフォルトのint*を使用します.特定のtypeタイプには使用されていないので、templateの後ろの内容は空です.では、この2つのクラスが正常に使用できるとどのように判断しますか?次の例を見てみましょう.249: data<int> p;
004013BD lea ecx,[ebp-10h]
004013C0 call @ILT+45(data<int>::data<int>) (00401032)
004013C5 mov dword ptr [ebp-4],0
250: data<int*> q;
004013CC lea ecx,[ebp-14h]
004013CF call @ILT+35(data<int *>::data<int *>) (00401028)
251: }
最初の関数のcallアドレスは0 x 0401032であり、2番目のアドレスは0 x 0401028であることが分かった.しかし、これは何も説明できません.2番目のアドレスも最初のテンプレートクラスが引用した可能性があります.私たちは各関数に従うべきです(実はここのアドレスはVCの下でジャンプアドレスです).最初の変数の実際の入力関数は次のとおりです.
234: data() {printf("normal!
");}
00401340 push ebp
00401341 mov ebp,esp
00401343 sub esp,44h
00401346 push ebx
00401347 push esi
00401348 push edi
00401349 push ecx
0040134A lea edi,[ebp-44h]
0040134D mov ecx,11h
00401352 mov eax,0CCCCCCCCh
00401357 rep stos dword ptr [edi]
00401359 pop ecx
0040135A mov dword ptr [ebp-4],ecx
0040135D push offset string "normal!
" (0042607c)
00401362 call printf (00401540)
00401367 add esp,4
0040136A mov eax,dword ptr [ebp-4]
0040136D pop edi
0040136E pop esi
0040136F pop ebx
00401370 add esp,44h
00401373 cmp ebp,esp
00401375 call __chkesp (004023b0)
0040137A mov esp,ebp
0040137C pop ebp
0040137D ret
では、2番目の変数は、同じように関数を追加する必要があります.242: data() {printf("point!
");}
00401430 push ebp
00401431 mov ebp,esp
00401433 sub esp,44h
00401436 push ebx
00401437 push esi
00401438 push edi
00401439 push ecx
0040143A lea edi,[ebp-44h]
0040143D mov ecx,11h
00401442 mov eax,0CCCCCCCCh
00401447 rep stos dword ptr [edi]
00401449 pop ecx
0040144A mov dword ptr [ebp-4],ecx
0040144D push offset string "point!
" (00426074)
00401452 call printf (00401540)
00401457 add esp,4
0040145A mov eax,dword ptr [ebp-4]
0040145D pop edi
0040145E pop esi
0040145F pop ebx
00401460 add esp,44h
00401463 cmp ebp,esp
00401465 call __chkesp (004023b0)
0040146A mov esp,ebp
0040146C pop ebp
0040146D ret
上の関数を見ると、両者が呼び出す構造関数が異なることがわかります.したがって、特化テンプレートは通常、特殊なデータ型のために用意されています.これにより,我々利用者はテンプレートを使用する際に何の心配もなく,各データ型処理の違いを無視できる.もちろん、特化テンプレートは特殊なモデルデータを考慮しているため、私たちのコードがより完成し、より丈夫になりました.テンプレートを設計するときに適切に多く使用することをお勧めします.思考問題:
(1)テンプレートクラスの最初のtypeはデフォルトでよろしいですか?なぜそう考えるのですか?
(2)次のコードはvc 6.0とvc 2005でコンパイルできますか?なぜですか?私たちの設計コードについてどう思いますか?(互換性の面から考えることをお勧めします)
template <typename type>
class data
{
public:
data() {printf("normal!
");}
~data() {printf("~normal!
");}
};
template <typename type>
class data <type*>
{
public:
data() {printf("point!
");}
~data() {printf("point!
");}
};
【予告:次の2つのブログはとても面白いです.再帰テンプレートとテンプレートのテンプレートの内容を紹介します】