论坛 产品库 视频 专题 CIO俱乐部 Windows8 实验室 CMO俱乐部 案例

C语言类一定要有构造函数吗

发布时间:2013-06-19 00:00:00 来源:比特网 作者:悠虎
关键字:C语言

  1:任何类如果没有定义默认构造函数,就会合成出来?

  2:合成出来的默认构造函数会明确设定类内每一个成员的值?

  3:如何去证明呢?

  如果你对1、2回答的都是不是,请跳过阅读,以免浪费你的时间

  对于问题1与2其实答案都是未必,C++标准是这样写的默认构造函数是由编译器在需要的时候将其合成出来,这里强调的是需要,而非必需,以程序示例:

  [cpp]

  #include

  #include

  using namespace std;

  class A

  {

  public:

  char *ptr;

  //string str;

  };

  int main()

  {

  A b;

  b.ptr=NULL;

  return 0;

  }

  #include

  #include

  using namespace std;

  class A

  {

  public:

  char *ptr;

  //string str;

  };

  int main()

  {

  A b;

  b.ptr=NULL;

  return 0;

  }这个程序本身没什么好讲的,能讲的就是其汇编代码,调试状态下进入汇编代码如下:

  [cpp]

  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: }

  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个字节

  将程序注释中的

  [cpp]

  //string str;

  //string str;

  去掉,再次进入汇编看看,代码如下:

  [html]

  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: }

  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里,其形式如下:

  [cpp]

  typedef basic_string, allocator >

  string;

  typedef basic_string, allocator >

  string;这是一个模板类,属于STL范畴,不信你看看SGI STL源码,在机会再讲,继教跟踪,你会发现basic_string有一系列的构造函数,如下:

  [html]

  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); }

  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:继承虚基类的类


比特微信账号
比特微信账号

微信扫一扫
关注Chinabyte

返回首页 长微博 返回顶部