第2章构造函数语意学

来源:互联网 发布:海量数据处理 java 编辑:程序博客网 时间:2024/05/15 17:11

2.1Default Constructor的建构操作

“default constructors在需要的时候被编译器产生出来”

程序的需要和编译器的需要。

程序的需要,是程序员的责任。

当编译需要的时候,才会合成出来default constructor。被合成出来的constructor只执行编译器所需要的行动。

 

"对于class X,如果没有任何user-declared-constructor,那么会有一个default constructor被暗中(implicitly)声明出来......一个被暗中声明出来的default constructor将是一个trivial constructor"

举例:

//test.cpp

 

class Foo{

public:

  int val;

  Foo * pnext;

};

int main(){

  Foo myFoo;

  return 0;

}

// 反汇编

objdump -dC test.o

 

// 输出内容

test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <main>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 10             sub    $0x10,%esp
   6:b8 00 00 00 00       mov    $0x0,%eax
   b:c9                   leave  
   c:c3                   ret   
// 可以看到没有产生default constructor
nontrivial default constructor
1."带有default constructor"的member class object
如果一个class没有任何constructor,但它内含一个member object,而后者有default constructo,那么这个class的implicit default constructor就是“nontrivial”,编译器需要为此class合成一个default construtor
举例:
//test.cpp
class Foo{
public:
  Foo();
  int val;
  Foo * pnext;
};
Foo::Foo(){
}
class Bar{
public:
  Foo foo;
  char *str;
};
int main(){
  Bar myBar;
  return 0;
}
//反汇编
objdump -dC test.o
test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <Foo::Foo()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:5d                   pop    %ebp
   4:c3                   ret    
00000005 <main>:
   5:55                   push   %ebp
   6:89 e5                mov    %esp,%ebp
   8:83 e4 f0             and    $0xfffffff0,%esp
   b:83 ec 20             sub    $0x20,%esp
   e:8d 44 24 14          lea    0x14(%esp),%eax
  12:89 04 24             mov    %eax,(%esp)
  15:e8 fc ff ff ff       call   16 <main+0x11>
  1a:b8 00 00 00 00       mov    $0x0,%eax
  1f:c9                   leave  
  20:c3                   ret    
Disassembly of section .text._ZN3BarC2Ev:
00000000 <Bar::Bar()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 04             sub    $0x4,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:89 04 24             mov    %eax,(%esp)
   c:e8 fc ff ff ff       call   d <Bar::Bar()+0xd>
  11:c9                   leave  
  12:c3                   ret    
class的default constructor会依次序调用成员object的constructor
“如果class A内含一个或一个以上的member class objects,那么class A的每一个constructor必须调用每一个member classes的default constructor”
2."带有default constructor的"base class
如果一个没有任何constructor的class派生自一个“带有default constructor”的base class,那么这个derived class的default constructor会被视为nontrivial,并因此需要被合成出来。它将调用上一层base classes的defualt constructor。对一个后续派生的class而言,这个合成的constructor和一个“被明确提供的default constructor"没有什么差异。
//test.cpp
class Foo{
public:
  Foo();
  int val;
  Foo * pnext;
};
Foo::Foo(){
}
class Bar: public Foo{
public:
  char *str;
};
int main(){
  Bar myBar;
  return 0;
}
//反汇编
objdump -dC test.o
test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <Foo::Foo()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:5d                   pop    %ebp
   4:c3                   ret    
00000005 <main>:
   5:55                   push   %ebp
   6:89 e5                mov    %esp,%ebp
   8:83 e4 f0             and    $0xfffffff0,%esp
   b:83 ec 20             sub    $0x20,%esp
   e:8d 44 24 14          lea    0x14(%esp),%eax
  12:89 04 24             mov    %eax,(%esp)
  15:e8 fc ff ff ff       call   16 <main+0x11>
  1a:b8 00 00 00 00       mov    $0x0,%eax
  1f:c9                   leave  
  20:c3                   ret    
Disassembly of section .text._ZN3BarC2Ev:
00000000 <Bar::Bar()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 04             sub    $0x4,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:89 04 24             mov    %eax,(%esp)
   c:e8 fc ff ff ff       call   d <Bar::Bar()+0xd>
  11:c9                   leave  
  12:c3                   ret    
4."带有一个virtual function"的class
同理
class Widget{
public:
  virtual void flip() = 0;
};
class Bell:public Widget{
public:
  virtual void flip();
};
void Bell::flip(){}
class Whistle:public Widget{
public:
  virtual void flip();
};
void Whistle::flip(){}
int main(){
  Bell mybell;
  Whistle mywhistle;
  return 0;
}
//反汇编
test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <Bell::flip()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:5d                   pop    %ebp
   4:c3                   ret    
   5:90                   nop
00000006 <Whistle::flip()>:
   6:55                   push   %ebp
   7:89 e5                mov    %esp,%ebp
   9:5d                   pop    %ebp
   a:c3                   ret    
0000000b <main>:
   b:55                   push   %ebp
   c:89 e5                mov    %esp,%ebp
   e:83 e4 f0             and    $0xfffffff0,%esp
  11:83 ec 20             sub    $0x20,%esp
  14:8d 44 24 1c          lea    0x1c(%esp),%eax
  18:89 04 24             mov    %eax,(%esp)
  1b:e8 fc ff ff ff       call   1c <main+0x11>
  20:8d 44 24 18          lea    0x18(%esp),%eax
  24:89 04 24             mov    %eax,(%esp)
  27:e8 fc ff ff ff       call   28 <main+0x1d>
  2c:b8 00 00 00 00       mov    $0x0,%eax
  31:c9                   leave  
  32:c3                   ret    
Disassembly of section .text._ZN6WidgetC2Ev:
00000000 <Widget::Widget()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:8b 45 08             mov    0x8(%ebp),%eax
   6:c7 00 08 00 00 00    movl   $0x8,(%eax)
   c:5d                   pop    %ebp
   d:c3                   ret    
Disassembly of section .text._ZN4BellC2Ev:
00000000 <Bell::Bell()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 18             sub    $0x18,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:89 04 24             mov    %eax,(%esp)
   c:e8 fc ff ff ff       call   d <Bell::Bell()+0xd>
  11:8b 45 08             mov    0x8(%ebp),%eax
  14:c7 00 08 00 00 00    movl   $0x8,(%eax)
  1a:c9                   leave  
  1b:c3                   ret    
Disassembly of section .text._ZN7WhistleC2Ev:
00000000 <Whistle::Whistle()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 18             sub    $0x18,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:89 04 24             mov    %eax,(%esp)
   c:e8 fc ff ff ff       call   d <Whistle::Whistle()+0xd>
  11:8b 45 08             mov    0x8(%ebp),%eax
  14:c7 00 08 00 00 00    movl   $0x8,(%eax)
  1a:c9                   leave  
  1b:c3                   ret    
//但是如果不掉用Bell,Whister
int main(){
  //Bell mybell;
  //Whistle mywhistle;
  return 0;
}
//反汇编
test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <Bell::flip()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:5d                   pop    %ebp
   4:c3                   ret    
   5:90                   nop
00000006 <Whistle::flip()>:
   6:55                   push   %ebp
   7:89 e5                mov    %esp,%ebp
   9:5d                   pop    %ebp
   a:c3                   ret    
0000000b <main>:
   b:55                   push   %ebp
   c:89 e5                mov    %esp,%ebp
   e:b8 00 00 00 00       mov    $0x0,%eax
  13:5d                   pop    %ebp
  14:c3                   ret  
没有出现任何构造函数,只有需要的时候才会构造
一个virtual function table会被编译器产生出来,内放class的virtual functions地址。
在每一个class object中,一个额外的pointer member会被编译器合成出来,内含相关的class vtbl的地址。
对于那些未声明任何constructor的classes,编译器会为它们合成一个default constructor,以便正确地初始化每一个class object的vptr
4."带有一个virtual base class"的class
//test.cpp
class X{
public:
  int i;
};
class A:public virtual X{
public:
  int j;
};
class B:public virtual X{
public:
  double d;
};
class C:public A, public B{
public:
  int k;
};
void foo(A* pa){
  pa->i = 1024;
}
int main(){
  foo(new A);
  foo(new C);
  return 0;
}
//反汇编
test.o:     file format elf32-i386
Disassembly of section .text:
00000000 <foo(A*)>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:8b 55 08             mov    0x8(%ebp),%edx
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:8b 00                mov    (%eax),%eax
   b:83 e8 0c             sub    $0xc,%eax
   e:8b 00                mov    (%eax),%eax
  10:8d 04 02             lea    (%edx,%eax,1),%eax
  13:c7 00 00 04 00 00    movl   $0x400,(%eax)
  19:5d                   pop    %ebp
  1a:c3                   ret    
0000001b <main>:
  1b:55                   push   %ebp
  1c:89 e5                mov    %esp,%ebp
  1e:83 e4 f0             and    $0xfffffff0,%esp
  21:53                   push   %ebx
  22:83 ec 1c             sub    $0x1c,%esp
  25:c7 04 24 0c 00 00 00 movl   $0xc,(%esp)
  2c:e8 fc ff ff ff       call   2d <main+0x12>
  31:89 c3                mov    %eax,%ebx
  33:89 d8                mov    %ebx,%eax
  35:89 04 24             mov    %eax,(%esp)
  38:e8 fc ff ff ff       call   39 <main+0x1e>
  3d:89 d8                mov    %ebx,%eax
  3f:89 04 24             mov    %eax,(%esp)
  42:e8 fc ff ff ff       call   43 <main+0x28>
  47:c7 04 24 1c 00 00 00 movl   $0x1c,(%esp)
  4e:e8 fc ff ff ff       call   4f <main+0x34>
  53:89 c3                mov    %eax,%ebx
  55:89 d8                mov    %ebx,%eax
  57:89 04 24             mov    %eax,(%esp)
  5a:e8 fc ff ff ff       call   5b <main+0x40>
  5f:89 d8                mov    %ebx,%eax
  61:89 04 24             mov    %eax,(%esp)
  64:e8 fc ff ff ff       call   65 <main+0x4a>
  69:b8 00 00 00 00       mov    $0x0,%eax
  6e:83 c4 1c             add    $0x1c,%esp
  71:5b                   pop    %ebx
  72:89 ec                mov    %ebp,%esp
  74:5d                   pop    %ebp
  75:c3                   ret    
Disassembly of section .text._ZN1XC2Ev:
00000000 <X::X()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:5d                   pop    %ebp
   4:c3                   ret    
Disassembly of section .text._ZN1AC2Ev:
00000000 <A::A()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:8b 45 0c             mov    0xc(%ebp),%eax
   6:8b 00                mov    (%eax),%eax
   8:89 c2                mov    %eax,%edx
   a:8b 45 08             mov    0x8(%ebp),%eax
   d:89 10                mov    %edx,(%eax)
   f:5d                   pop    %ebp
  10:c3                   ret    
Disassembly of section .text._ZN1AC1Ev:
00000000 <A::A()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 18             sub    $0x18,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:83 c0 08             add    $0x8,%eax
   c:89 04 24             mov    %eax,(%esp)
   f:e8 fc ff ff ff       call   10 <A::A()+0x10>
  14:b8 00 00 00 00       mov    $0x0,%eax
  19:8d 50 0c             lea    0xc(%eax),%edx
  1c:8b 45 08             mov    0x8(%ebp),%eax
  1f:89 10                mov    %edx,(%eax)
  21:c9                   leave  
  22:c3                   ret    
Disassembly of section .text._ZN1BC2Ev:
00000000 <B::B()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:8b 45 0c             mov    0xc(%ebp),%eax
   6:8b 00                mov    (%eax),%eax
   8:89 c2                mov    %eax,%edx
   a:8b 45 08             mov    0x8(%ebp),%eax
   d:89 10                mov    %edx,(%eax)
   f:5d                   pop    %ebp
  10:c3                   ret    
Disassembly of section .text._ZN1CC1Ev:
00000000 <C::C()>:
   0:55                   push   %ebp
   1:89 e5                mov    %esp,%ebp
   3:83 ec 18             sub    $0x18,%esp
   6:8b 45 08             mov    0x8(%ebp),%eax
   9:83 c0 18             add    $0x18,%eax
   c:89 04 24             mov    %eax,(%esp)
   f:e8 fc ff ff ff       call   10 <C::C()+0x10>
  14:b8 00 00 00 00       mov    $0x0,%eax
  19:8d 50 04             lea    0x4(%eax),%edx
  1c:8b 45 08             mov    0x8(%ebp),%eax
  1f:89 54 24 04          mov    %edx,0x4(%esp)
  23:89 04 24             mov    %eax,(%esp)
  26:e8 fc ff ff ff       call   27 <C::C()+0x27>
  2b:b8 00 00 00 00       mov    $0x0,%eax
  30:8d 50 08             lea    0x8(%eax),%edx
  33:8b 45 08             mov    0x8(%ebp),%eax
  36:83 c0 08             add    $0x8,%eax
  39:89 54 24 04          mov    %edx,0x4(%esp)
  3d:89 04 24             mov    %eax,(%esp)
  40:e8 fc ff ff ff       call   41 <C::C()+0x41>
  45:ba 0c 00 00 00       mov    $0xc,%edx
  4a:8b 45 08             mov    0x8(%ebp),%eax
  4d:89 10                mov    %edx,(%eax)
  4f:b8 00 00 00 00       mov    $0x0,%eax
  54:8d 50 18             lea    0x18(%eax),%edx
  57:8b 45 08             mov    0x8(%ebp),%eax
  5a:89 50 08             mov    %edx,0x8(%eax)
  5d:c9                   leave  
  5e:c3                   ret    
pa不能确定x::i的位置,只能在执行期决定。
在derived class object的每一个virtual base classed 中安插一个指针完成。
_vbcX是在class object建构期间完成的,对于与class所定义的每一个constructor,编译器会安插那些“允许每一个virtual base class的执行期存取操作”的码,如果class没有声明任何constructors,编译器必须为它合成一个default constructor

 

原创粉丝点击