1:C++類裡面無論如何都會有一個拷貝構造函數(隱含的或者顯示的),是這樣的嗎?
2:大學課本裡是這樣寫的若一個類不帶有拷貝構造函數,則系統為該類隱含定義一個拷貝構造函數(出自<<C++語言基礎教程>>第245頁)真是這樣的嗎?
當追根究底其實都是錯的,拷貝構造函數未必必須有,想想如果一個類一點都不復雜,編譯器還要定義一個拷貝構造函數,進行一次函數的調用操作,對程序運行的效率將是多麼大的傷害呀?
C++標准是這樣寫的:
默認拷貝構造函數是在必要的時候由編譯器進行合成的,這裡是在必要的時候而不是一定,不是嗎:)
證明:
程序一:
[cpp] view plaincopyprint?
class A
{
private:
int a;
char *str;
};
int main()
{
A a;
A b=a;
return 0;
}
class A
{
private:
int a;
char *str;
};
int main()
{
A a;
A b=a;
return 0;
}按照書中寫的,在A b=a時會發生拷貝構造函數的調用操作,是這樣的吧:),讓我們進入匯編代碼看看真的是這樣的嗎,調試進入匯編代碼運行
[cpp] view plaincopyprint?
11: A a;
12: A b=a;
00401048 mov eax,dword ptr [ebp-8]
0040104B mov dword ptr [ebp-10h],eax
0040104E mov ecx,dword ptr [ebp-4]
00401051 mov dword ptr [ebp-0Ch],ecx
11: A a;
12: A b=a;
00401048 mov eax,dword ptr [ebp-8]
0040104B mov dword ptr [ebp-10h],eax
0040104E mov ecx,dword ptr [ebp-4]
00401051 mov dword ptr [ebp-0Ch],ecx你看到有A:A( A &a)這樣的函數調用操作嗎?我是沒有看到:),有的只是通過寄存器以及堆棧操作來進行的復制操作(即按比特位進行的復制操作),拷貝構造函數是不會產生的。
程序二:
class A { private: int a; string str; }; int main() { A a; A b=a; return 0; } class A { private: int a; string str; }; int main() { A a; A b=a; return 0;
}同樣,按照書中寫的,在A b=a時會發生拷貝構造函數的調用操作,是這樣的吧:),讓我們進入匯編代碼看看真的是這樣的嗎,調試進入匯編代碼運行
11: A a; 0040117D lea ecx,[ebp-20h] 00401180 call @ILT+55(A::A) (0040103c) 00401185 mov dword ptr [ebp-4],0 12: A b=a; 0040118C lea eax,[ebp-20h] 0040118F push eax 00401190 lea ecx,[ebp-34h] 00401193 call @ILT+140(A::A) (00401091) 13: return 0; 11: A a; 0040117D lea ecx,[ebp-20h] 00401180 call @ILT+55(A::A) (0040103c) 00401185 mov dword ptr [ebp-4],0 12: A b=a; 0040118C lea eax,[ebp-20h] 0040118F push eax 00401190 lea ecx,[ebp-34h] 00401193 call @ILT+140(A::A) (00401091) 13: return 0;
你看到有A:A( A &a)這樣的函數調用操作嗎?看到了吧,拷貝構造函數產生了,這是為什麼呢。
<SPAN style="FONT-SIZE: 18px">A::A: 004012A0 push ebp 004012A1 mov ebp,esp 004012A3 sub esp,44h 004012A6 push ebx 004012A7 push esi 004012A8 push edi 004012A9 push ecx 004012AA lea edi,[ebp-44h] 004012AD mov ecx,11h 004012B2 mov eax,0CCCCCCCCh 004012B7 rep stos dword ptr [edi] 004012B9 pop ecx 004012BA mov dword ptr [ebp-4],ecx 004012BD mov eax,dword ptr [ebp-4] 004012C0 mov ecx,dword ptr [ebp+8] 004012C3 mov edx,dword ptr [ecx] 004012C5 mov dword ptr [eax],edx 004012C7 mov eax,dword ptr [ebp+8] 004012CA add eax,4 004012CD push eax 004012CE mov ecx,dword ptr [ebp-4] 004012D1 add ecx,4 <SPAN style="COLOR: #ff0000">004012D4 call @ILT+150(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_str </SPAN>004012D9 mov eax,dword ptr [ebp-4] 004012DC pop edi 004012DD pop esi 004012DE pop ebx 004012DF add esp,44h 004012E2 cmp ebp,esp </SPAN> A::A: 004012A0 push ebp 004012A1 mov ebp,esp 004012A3 sub esp,44h 004012A6 push ebx 004012A7 push esi 004012A8 push edi 004012A9 push ecx 004012AA lea edi,[ebp-44h] 004012AD mov ecx,11h 004012B2 mov eax,0CCCCCCCCh 004012B7 rep stos dword ptr [edi] 004012B9 pop ecx 004012BA mov dword ptr [ebp-4],ecx 004012BD mov eax,dword ptr [ebp-4] 004012C0 mov ecx,dword ptr [ebp+8] 004012C3 mov edx,dword ptr [ecx] 004012C5 mov dword ptr [eax],edx 004012C7 mov eax,dword ptr [ebp+8] 004012CA add eax,4 004012CD push eax 004012CE mov ecx,dword ptr [ebp-4] 004012D1 add ecx,4 004012D4 call @ILT+150(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_str 004012D9 mov eax,dword ptr [ebp-4] 004012DC pop edi 004012DD pop esi 004012DE pop ebx 004012DF add esp,44h 004012E2 cmp ebp,esp
看到了沒,紅色的,這是因為成員類對象含有拷貝構造函數,所以編譯器要合成一個拷貝構造函數用以調用成員類對象的拷貝構造函數,對類對象的數據成員進行復制操作
其實上面的程序一構造函數與析構函數均不會合成,可以看一下這篇博客C++類一定有構造函數嗎
在以下四種情況會產生默認拷貝構造函數
1:類的成員類對象有拷貝構造函數
2:類繼承的基類含有拷貝構造函數
3:類含有虛函數
4:類繼承於虛基類