歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++類一定有構造函數嗎

1:任何類如果沒有定義默認構造函數,就會合成出來?

2:合成出來的默認構造函數會明確設定類內每一個成員的值?

3:如何去證明呢?

如果你對1、2回答的都是不是,請跳過閱讀,以免浪費你的時間

對於問題1與2其實答案都是未必,C++標准是這樣寫的默認構造函數是由編譯器在需要的時候將其合成出來,這裡強調的是需要,而非必需,以程序示例:

#include<iostream>
#include<string>
using namespace std;
class A
{
public:
  char *ptr;
  //string str;
};
int main()
{
 A b;
 b.ptr=NULL;
 return 0;
}

這個程序本身沒什麼好講的,能講的就是其匯編代碼,調試狀態下進入匯編代碼如下:

11:  {
00401030  push        ebp
00401031  mov        ebp,esp
00401033  sub        esp,44h
00401036  push        ebx
00401037  push        esi
00401038  push        edi
00401039  lea        edi,[ebp-44h]
0040103C  mov        ecx,11h
00401041  mov        eax,0CCCCCCCCh
00401046  rep stos    dword ptr [edi]
12:      A b;
13:      b.ptr=NULL;
00401048  mov        dword ptr [ebp-4],0
14:      return 0;
0040104F  xor        eax,eax
15:  }

你能找到構造函數調用的地方嗎即A::A(),:),找不到吧,因為壓根就沒有構造函數,這個類就相當於一個整形變量(存儲上相似,用法上不同),其空間是堆棧ebp+4這裡的4個字節

將程序注釋中的

 //string str;

去掉,再次進入匯編看看,代碼如下:

10:  int main()
11:  {
00401070  push        ebp
00401071  mov        ebp,esp
00401073  sub        esp,58h
00401076  push        ebx
00401077  push        esi
00401078  push        edi
00401079  lea        edi,[ebp-58h]
0040107C  mov        ecx,16h
00401081  mov        eax,0CCCCCCCCh
00401086  rep stos    dword ptr [edi]
12:      A b;
00401088  lea        ecx,[ebp-14h]
0040108B  call        @ILT+15(A::A) (00401014)
13:      b.ptr=NULL;
00401090  mov        dword ptr [ebp-14h],0
14:      return 0;
00401097  mov        dword ptr [ebp-18h],0
0040109E  lea        ecx,[ebp-14h]
004010A1  call        @ILT+30(A::~A) (00401023)
004010A6  mov        eax,dword ptr [ebp-18h]
15:  }

看看,我們的構造函數出現了吧A:A() :),為什麼會出現呢?
因為類裡面有一個類叫string,我們跟蹤發現string類定義在include/xstring裡,其形式如下:

typedef basic_string<char, char_traits<char>, allocator<char> >
 string;

這是一個模板類,屬於STL范疇,不信你看看SGI STL源碼,在機會再講,繼教跟蹤,你會發現basic_string有一系列的構造函數,如下:

 explicit basic_string(const _A& _Al = _A())
  : allocator(_Al) {_Tidy(); }
 basic_string(const _Myt& _X)
  : allocator(_X.allocator)
  {_Tidy(), assign(_X, 0, npos); }
 basic_string(const _Myt& _X, size_type _P, size_type _M,
  const _A& _Al = _A())
  : allocator(_Al) {_Tidy(), assign(_X, _P, _M); }
 basic_string(const _E *_S, size_type _N,
  const _A& _Al = _A())
  : allocator(_Al) {_Tidy(), assign(_S, _N); }
 basic_string(const _E *_S, const _A& _Al = _A())
  : allocator(_Al) {_Tidy(), assign(_S); }
 basic_string(size_type _N, _E _C, const _A& _Al = _A())
  : allocator(_Al) {_Tidy(), assign(_N, _C); }

其實重要的是第一個構造函數,因為此處調用就是它,給basic_string分配一個內存分配管理器:)

明白了吧,此處有是因為類裡面有一個string類的對象,別人屬於你,別人有自已的構造函數,需要為其賦一個初始值,你總不能不讓吧,於是編譯器就合成一個默認的構造函數,調用string裡的構造函數,為string對像置一個初始狀態

構造函數的確是不一定會有的,而且類裡的一些內置類型默認構造函數也不會給其設定一個默認值的,不信你再看看匯編,哪裡有對ptr的賦值:)

有四種情況編譯器會為合成默認構造函數

1:含有默認默認/構造函數的成員類對象

2:帶有默認/構造函數的基類對象

3: 含有虛函數的類

4:繼承虛基類的類

可以參考此書《深入理解C++對象模型》第二章 下載見 http://www.linuxidc.com/Linux/2012-03/56159.htm

Copyright © Linux教程網 All Rights Reserved