C++: 编译器何时构建或扩展默认构造函数 Default Constructor
扫描二维码
随时随地手机看文章
《深度探索C++对象模型》一书第二章关于编译器构建或扩展构造函数的结尾指出,对于我们C++新手有两个常见的误解:
1,任何没有定义default constructor的class,编译器都会自动替程序员合成一个出来;
2,编译器合成出来的default constructor会默认对class的数据成员进行初始化。
然而,事实上并非如此,但是有很多地方我们确实见到过这种说法呀,到底什么时候编译器会为我们做这个事情呢?书中总结了四种情况下,编译器会为了需要合成或者扩展构造函数:
1,class中有data member是某class的object,并且此object所属的class有default constructor;
2,class继承自有default constructor的base class;
3,class中定义了virtual function或者继承有virtual function,编译器需要为此类object初始化virtual function table;
4,class以virtual方式继承base class。
第二种情况是最简单的,如果class没有定义某class类型的object data member,同时没有virtual function和virtual base class,则如果此class没有定义默认构造函数,有两种情况发生:1,如果定义有其他带参数构造函数,则创建对象时必须传入参数,而不管其继承的base class是否有默认构造函数,否则会报找不到构造函数的错误;2,如果没有定义任何构造函数,并且其继承的base class有默认构造函数,则编译器会为其合成默认构造函数,但是不会对其基本数据类型的数据成员初始化。
class BaseA{ }; class ChildB:public BaseA{ public: }; int main() { ChildB child; return 0; }
class BaseA{ public: BaseA() {} }; class ChildB:public BaseA{ public: }; int main() { ChildB child; return 0; }
编译结果:
##################################
.file "testdef.cpp"
.text
.globl
main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
.file"testinh.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB5:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC2Ev
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE5:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size main, .-main
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
由此对比,Child Class的默认构造函数由编译器自动构造出来了。
针对第一种情况,如果class定义了某个object成员,此object所属类有默认构造函数,则:
1,如果class中无构造函数,则编译器将自动合成默认构造函数,并初始化object成员
class BaseA{ public: BaseA() {} }; class ChildB{ public: BaseA basea; }; int main() { ChildB child; return 0; }
class BaseA{ public: BaseA() {} }; class ChildB{ public: ChildB() {} BaseA basea; }; int main() { ChildB child; return 0; }
编译结果:
.file
"testdef.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB5:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC1Ev
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE5:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size main, .-main
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
.file
"testinh.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC1Ev
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE4:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size main, .-main
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
2,若class中提供了任意构造函数,但是未对object成员初始化,则编译器将在构造函数中插入object成员的初始化操作,即扩展已有的构造函数
class BaseA{ public: BaseA() {} }; class ChildB{ public: ChildB() {} BaseA basea; }; int main() { ChildB child; return 0; }
class BaseA{ public: BaseA() {} }; class ChildB{ public: ChildB():basea() {} BaseA basea; }; int main() { ChildB child; return 0; }
编译结果
.file
"testinh.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC1Ev
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE4:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size main, .-main
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
.file
"testdef.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC1Ev
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE4:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size main, .-main
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
第三种情况,class中定义有virtual function或者继承链中有类定义了virtual function,编译器需要为class类型的对象创建vtl和vptr,因此编译器将自动合成默认构造函数
class ChildB{ public: virtual void func() {} }; int main() { ChildB child; return 0; }
class ChildB{ public: ChildB() {} virtual void func() {} }; int main() { ChildB child; return 0; }
编译结果
.file
"testdef.cpp"
.section
.text._ZN6ChildB4funcEv,"axG",@progbits,_ZN6ChildB4funcEv,comdat
.align 2
.weak _ZN6ChildB4funcEv
.type _ZN6ChildB4funcEv, @function
_ZN6ChildB4funcEv:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size _ZN6ChildB4funcEv, .-_ZN6ChildB4funcEv
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq $_ZTV6ChildB+16, (%rax)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.text
.globl
main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -16(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.weak _ZTV6ChildB
.section
.rodata._ZTV6ChildB,"aG",@progbits,_ZTV6ChildB,comdat
.align 16
.type _ZTV6ChildB, @object
.size _ZTV6ChildB, 24
_ZTV6ChildB:
.quad 0
.quad _ZTI6ChildB
.quad _ZN6ChildB4funcEv
.weak _ZTS6ChildB
.section
.rodata._ZTS6ChildB,"aG",@progbits,_ZTS6ChildB,comdat
.type _ZTS6ChildB, @object
.size _ZTS6ChildB, 8
_ZTS6ChildB:
.string
"6ChildB"
.weak _ZTI6ChildB
.section
.rodata._ZTI6ChildB,"aG",@progbits,_ZTI6ChildB,comdat
.align 16
.type _ZTI6ChildB, @object
.size _ZTI6ChildB, 16
_ZTI6ChildB:
.quad _ZTVN10__cxxabiv117__class_type_infoE+16
.quad _ZTS6ChildB
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
.file
"testinh.cpp"
.section
.text._ZN6ChildBC2Ev,"axG",@progbits,_ZN6ChildBC5Ev,comdat
.align 2
.weak _ZN6ChildBC2Ev
.type _ZN6ChildBC2Ev, @function
_ZN6ChildBC2Ev:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq $_ZTV6ChildB+16, (%rax)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size _ZN6ChildBC2Ev, .-_ZN6ChildBC2Ev
.section
.text._ZN6ChildB4funcEv,"axG",@progbits,_ZN6ChildB4funcEv,comdat
.align 2
.weak _ZN6ChildB4funcEv
.type _ZN6ChildB4funcEv, @function
_ZN6ChildB4funcEv:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size _ZN6ChildB4funcEv, .-_ZN6ChildB4funcEv
.text
.globl
main
.type main, @function
main:
.LFB4:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -16(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE4:
.size main, .-main
.weak _ZTV6ChildB
.section
.rodata._ZTV6ChildB,"aG",@progbits,_ZTV6ChildB,comdat
.align 16
.type _ZTV6ChildB, @object
.size _ZTV6ChildB, 24
_ZTV6ChildB:
.quad 0
.quad _ZTI6ChildB
.quad _ZN6ChildB4funcEv
.weak _ZTS6ChildB
.section
.rodata._ZTS6ChildB,"aG",@progbits,_ZTS6ChildB,comdat
.type _ZTS6ChildB, @object
.size _ZTS6ChildB, 8
_ZTS6ChildB:
.string
"6ChildB"
.weak _ZTI6ChildB
.section
.rodata._ZTI6ChildB,"aG",@progbits,_ZTI6ChildB,comdat
.align 16
.type _ZTI6ChildB, @object
.size _ZTI6ChildB, 16
_ZTI6ChildB:
.quad _ZTVN10__cxxabiv117__class_type_infoE+16
.quad _ZTS6ChildB
.weak _ZN6ChildBC1Ev
.set _ZN6ChildBC1Ev,_ZN6ChildBC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
第四种情况,class以virtual方式继承,或者其继承链中有virtual方式的继承,编译器为此class和base class均自动合成默认构造函数
class BaseA{ }; class ChildB:public BaseA{ }; int main() { ChildB child; return 0; }
class BaseA{ }; class ChildB: virtual public BaseA{ }; int main() { ChildB child; return 0; }
编译结果
#############################################
.file "testinh.cpp"
.text
.globl
main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
.file
"testdef.cpp"
.section
.text._ZN5BaseAC2Ev,"axG",@progbits,_ZN5BaseAC5Ev,comdat
.align 2
.weak _ZN5BaseAC2Ev
.type _ZN5BaseAC2Ev, @function
_ZN5BaseAC2Ev:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE3:
.size _ZN5BaseAC2Ev, .-_ZN5BaseAC2Ev
.section
.text._ZN6ChildBC1Ev,"axG",@progbits,_ZN6ChildBC1Ev,comdat
.align 2
.weak _ZN6ChildBC1Ev
.type _ZN6ChildBC1Ev, @function
_ZN6ChildBC1Ev:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN5BaseAC2Ev
movl $_ZTV6ChildB+24, %edx
movq -8(%rbp), %rax
movq %rdx, (%rax)
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size _ZN6ChildBC1Ev, .-_ZN6ChildBC1Ev
.text
.globl
main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -16(%rbp), %rax
movq %rax, %rdi
call _ZN6ChildBC1Ev
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.weak _ZTV6ChildB
.section
.rodata._ZTV6ChildB,"aG",@progbits,_ZTV6ChildB,comdat
.align 16
.type _ZTV6ChildB, @object
.size _ZTV6ChildB, 24
_ZTV6ChildB:
.quad 0
.quad 0
.quad _ZTI6ChildB
.weak _ZTT6ChildB
.section
.rodata._ZTT6ChildB,"aG",@progbits,_ZTV6ChildB,comdat
.align 8
.type _ZTT6ChildB, @object
.size _ZTT6ChildB, 8
_ZTT6ChildB:
.quad _ZTV6ChildB+24
.weak _ZTS6ChildB
.section
.rodata._ZTS6ChildB,"aG",@progbits,_ZTS6ChildB,comdat
.type _ZTS6ChildB, @object
.size _ZTS6ChildB, 8
_ZTS6ChildB:
.string
"6ChildB"
.weak _ZTI6ChildB
.section
.rodata._ZTI6ChildB,"aG",@progbits,_ZTI6ChildB,comdat
.align 32
.type _ZTI6ChildB, @object
.size _ZTI6ChildB, 40
_ZTI6ChildB:
.quad _ZTVN10__cxxabiv121__vmi_class_type_infoE+16
.quad _ZTS6ChildB
.long 0
.long 1
.quad _ZTI5BaseA
.quad -6141
.weak _ZTS5BaseA
.section
.rodata._ZTS5BaseA,"aG",@progbits,_ZTS5BaseA,comdat
.type _ZTS5BaseA, @object
.size _ZTS5BaseA, 7
_ZTS5BaseA:
.string
"5BaseA"
.weak _ZTI5BaseA
.section
.rodata._ZTI5BaseA,"aG",@progbits,_ZTI5BaseA,comdat
.align 16
.type _ZTI5BaseA, @object
.size _ZTI5BaseA, 16
_ZTI5BaseA:
.quad _ZTVN10__cxxabiv117__class_type_infoE+16
.quad _ZTS5BaseA
.weak _ZN5BaseAC1Ev
.set _ZN5BaseAC1Ev,_ZN5BaseAC2Ev
.ident
"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section
.note.GNU-stack,"",@progbits
但是对于上述说的第一种误解,我是没有真正理解的,如果没有构造函数,编译器也不自动合成,对象是如何建立的?
#includeusing namespace std; class NoDef{ public: int k; void print() { cout << "k is " << k << endl;} }; int main() { NoDef def; def.print(); def.k = 2; def.print(); def.k = 199566; def.print(); return 0; }
由于上方的代码可以执行,那么是否说明def对象创建了?如果为NoDef添加了默认构造函数,从编译结果看,main函数中明显调用了构造函数。理解还是不到位,继续找资料学习。