一 : 分析obj(目标文件) 构造函数语义
1.构造函数: 默认构造函数(缺省构造函数) ; 没有参数的构造函数
2.如果我们没有定义任何构造函数,那么编译器就会为我们默认隐式自动定义一个构造函数(合成的构造函数
3.但是这种合成默认构造函数 只有在必要的时候 编译器才合成出来,而不是必须为我们合成出来。
二 : 什么时候才是必要时候
1.每个.cpp源文件会编译生成一个.obj(linux gcc -c .o) ,最终把很多.obj(.o) 文件链接到一起生成一个可执行文件。
2.先生成一段obj 然后通过VS自带的工具 开发人员命令提示符(Developer Command Prompr) 调试obj
class A{
public:
}
class B{
public:
int a;
int b;
void func(){
cout << "IAMVeryGood" <<endl;
}
}
int main(){
B b;
}
3.ctrl b 这个文件然后我们打开生成的Debug文件找到和.cpp同名的.obj文件 然后我们使用上面提到的工具进入到debug中目录
4.dumpbin /all project100.obj > my.txt
5.我们CTRL F查找我们希望编译器为我们生成的 B::B(); 但是没有。
6.所以这种情况 编译器不会为我们生成对应的构造函数
二: 修改代码
class A{
public:
A(){}; // 默认构造函数
}
class B{
public:
int a;
int b;
A a;
void func(){
cout << "IAMVeryGood" <<endl;
}
}
int main(){
B b;
}
// 类B没有任何构造函数, 但是包含一个类类型的成员a, 而该对象所属类A 有一个缺省的构造函数
// 这个时候编译器就会给类B生成一个 "合成默认的构造函数", 这个合成构造函数的目的是调用A的构造函数
// 也就是编译器合成了类B的构造函数,并在其中 安插代码,调用类Ad额缺省构造函数
// 我们可以重复上述命令行操作 找到B::B();
三:第三种情况
1. 父类带有缺省构造函数,子类没有任何构造函数,那么父类这个缺省构造函数要被调用,所以编译器会为子类合成一个默认构造函数
2. 合成的目的: 调用父类的构造函数
class A{
public:
A(){}; // 默认构造函数
}
class B : public A{
public:
int a;
int b;
void func(){
cout << "IAMVeryGood" <<endl;
}
}
int main(){
B b; // 找生成的构造函数操作如上
}
四: 第四种情况
1. 如果一个类还有虚函数,但没有任何构造函数时候。
class B{
public:
int a;
int b;
void func(){
cout << "IAMVeryGood" <<endl;
}
virtual void viritualFunc(){
cout << "viritualFunc" <<endl;
}
}
// 因为有虚函数,所以编译器会合成一个构造函数,生成一个基于该类的虚函数表 (vftable( my.txt 可以找到
// ( 大约在2459行 : ... const B::`vftable‘ 这么个东西
// 然后把该类的虚函数表地址赋给类对象的虚函数指针 (赋值语句)
// 虚函数表的主要作用就是为了搞搞多态
// 当然 如果写了构造函数,则会给构造函数添加相应的虚函数表操作的代码
五: 第五种情况
1.如果一个类带有虚基类,编译器也会为它合成一个默认构造函数
class Grand(){
public:
}
class A : virtual public Grand{ // 有构造函数 (vbtable 虚基类表 和虚函数表不是一个东西
public:
}
class B : virtual public Grand{ // 有构造函数 (vbtable 虚基类表
public:
}
class C : public A, public B{ // 虚基类表首地址
public:
}
int main(){
C c;
}