合成的默认构造函数

/*
*   分析obj(目标文件),构造函数语义

构造函数:
1.默认构造函数(又叫缺省构造函数): 没有参数的构造函数
2.传统知识认为,若未定义任何构造函数,编译器会隐式自动定义一个默认构造函数,叫"合成的默认构造函数"
==>
结论: 只有在必要的时候,编译器才会自动定义一个"合成的默认构造函数"; 而不是必然或者必须才合成出来.
(重点为必要的时候是什么时候)

前提知识:
每个.cpp源文件经过编译器编译都会生成一个.obj(linux下.o)文件(目标文件,同时也是二进制文件), 最终把很多此类文件链接在一起,就会生成一个可执行文件.

步骤:(windows下)
1.生成obj
2.用dumpbin把.obj文件导出成可查看文件my.txt(COFF,即通用对象文件格式,Common Object File Format)
3.在my.txt中寻找MBTX::MBTX ==> 未找到 ==> 未合成出合成的默认构造函数

====>编译器在哪些时候会把默认的构造函数合成出来?
1.该类MBTX未有任何构造函数,担包含一个类类型的成员m,同时该成员所属于的类MATX有一个缺省构造函数:
    此时该类MBTX会合成一个默认的构造函数,在合成的默认构造函数中安插代码,为了调用类类型成员所属的类MATX的缺省构造函数MATX::MATX().
    注意,类MBTX中可含有若干个类类型的成员,而该类的合成的默认构造函数


*/
#include <iostream>
using namespace std;

class MATX
{
  public:
    MATX()//缺省构造函数
    {
        printf("I am MATX\n", this);
    }
};

class MBTX
{
  public:
    int c;
    int d;
    MATX m;//类类型成员变量
    void funB()
    {
        printf("Hello\n", this);
    }
};

int main(int, char**) 
{


    MBTX b;

    //输出:
    // I am MATX

    return 1;

}

/*
*   分析obj(目标文件),构造函数语义

// ====>编译器在哪些时候会把默认的构造函数合成出来?
// 1.该类MBTX未有任何构造函数,担包含一个类类型的成员m,同时该成员所属于的类MATX有一个缺省构造函数:
//     此时该类MBTX会合成一个默认的构造函数,在合成的默认构造函数中安插代码,为了调用类类型成员所属的类MATX的缺省构造函数MATX::MATX().
//     注意,类MBTX中可含有若干个类类型的成员,而该类的合成的默认构造函数

2.父类带缺省构造函数,子类没有任何构造函数.因为父类的缺省构造函数要被调用,所以编译器会为这个子类合成出一个默认构造函数
    合成的目的是为了调用父类的构造函数.换句话说,编译器合成了默认的构造函数,并在其中安插代码,调用其父类的缺省构造函数


*/
#include <iostream>
using namespace std;

class MATX
{
  public:
    MATX()//缺省构造函数
    {
        printf("I am MATX\n", this);
    }
};

class MBTXPARENT
{
  public:
    MBTXPARENT()
    {
        printf("Hello,i am MBTXPARENT\n");
    }
};


class MBTX: public MBTXPARENT
{
  public:
    int c;
    int d;
    // MATX m;//类类型成员变量
    void funB()
    {
        printf("Hello\n", this);
    }
};

int main(int, char**) 
{


    MBTX b;

    //输出:
    // Hello,i am MBTXPARENT

    return 1;

}

/*
*   分析obj(目标文件),构造函数语义

// ====>编译器在哪些时候会把默认的构造函数合成出来?
// 1.该类MBTX未有任何构造函数,担包含一个类类型的成员m,同时该成员所属于的类MATX有一个缺省构造函数:
//     此时该类MBTX会合成一个默认的构造函数,在合成的默认构造函数中安插代码,为了调用类类型成员所属的类MATX的缺省构造函数MATX::MATX().
//     注意,类MBTX中可含有若干个类类型的成员,而该类的合成的默认构造函数

// 2.父类带缺省构造函数,子类没有任何构造函数.因为父类的缺省构造函数要被调用,所以编译器会为这个子类合成出一个默认构造函数
//     合成的目的是为了调用父类的构造函数.换句话说,编译器合成了默认的构造函数,并在其中安插代码,调用其父类的缺省构造函数

3.如果一个类含有虚函数,但该类没有任何构造函数时
    当存在虚函数时:
        (1)编译器会自动生成一个基于该类的虚函数表vftable(表中的每一项都记录着此类中每一个虚函数的首地址,虚函数表是跟着类走的)
        (2)编译器合成了一个构造函数,并在其中安插代码:目的是把虚函数表地址赋给类对象的虚函数表指针(相当于编译器在合成的缺省构造函数中加了一句赋值语句).
            (而虚函数表指针可以看作表面上看不见的一个类的成员函数)
            ==>当有虚函数存在,且该类生成一个对象时,这个类所属的对象会自带一个看不见的虚函数表指针,此指针就指向与该类有关的虚函数表
            (而之所以这么麻烦,是因为虚函数的调用存在一个多态问题,所以需要用到虚函数表指针这个概念)
    
  注意: 若在该类中加上一个缺省构造函数,而此时编译不会自动生成一个合成的默认构造函数,但是会在该类中本来有的构造函数中加上一些东西:
        在生成对象时:
            假设该类继承了基类,则会在其中安插代码:目的是调用基类的构造函数;
            假设该类中有虚函数时,也会在其中安插代码:目的是生成虚函数表,以及把虚函数表地址赋给类对象的虚函数表指针;
        ==>当有自己的构造函数时,编译器会根据需要扩充构造函数
        ==>编译器干了很多事,有构造函数时,根据需要扩充构造函数,无构造函数时,需要情况下合成构造构造函数



*/
#include <iostream>
using namespace std;

class MATX
{
  public:
    MATX()//缺省构造函数
    {
        printf("I am MATX\n", this);
    }
};

class MBTX
{
  public:
    int c;
    int d;
    void funB()
    {
        printf("Hello,i am funB\n", this);
    }

    virtual void mvirtualfunc()
    {
        printf("Hello,i am mvirtualfunc\n", this);
    }
};

int main(int, char**) 
{


    MBTX b;

    //输出:
    // 无任何输出,但是保存my.txtx后可以搜索到MBTX合成的默认构造函数

    return 1;

}

/*
*   分析obj(目标文件),构造函数语义

// ====>编译器在哪些时候会把默认的构造函数合成出来?
// 1.该类MBTX未有任何构造函数,担包含一个类类型的成员m,同时该成员所属于的类MATX有一个缺省构造函数:
//     此时该类MBTX会合成一个默认的构造函数,在合成的默认构造函数中安插代码,为了调用类类型成员所属的类MATX的缺省构造函数MATX::MATX().
//     注意,类MBTX中可含有若干个类类型的成员,而该类的合成的默认构造函数

// 2.父类带缺省构造函数,子类没有任何构造函数.因为父类的缺省构造函数要被调用,所以编译器会为这个子类合成出一个默认构造函数
//     合成的目的是为了调用父类的构造函数.换句话说,编译器合成了默认的构造函数,并在其中安插代码,调用其父类的缺省构造函数

// 3.如果一个类含有虚函数,但该类没有任何构造函数时
//     当存在虚函数时:
//         (1)编译器会自动生成一个基于该类的虚函数表vftable(表中的每一项都记录着此类中每一个虚函数的首地址,虚函数表是跟着类走的)
//         (2)编译器合成了一个构造函数,并在其中安插代码:目的是把虚函数表地址赋给类对象的虚函数表指针(相当于编译器在合成的缺省构造函数中加了一句赋值语句).
//             (而虚函数表指针可以看作表面上看不见的一个类的成员函数)
//             ==>当有虚函数存在,且该类生成一个对象时,这个类所属的对象会自带一个看不见的虚函数表指针,此指针就指向与该类有关的虚函数表
//             (而之所以这么麻烦,是因为虚函数的调用存在一个多态问题,所以需要用到虚函数表指针这个概念)
    
//   注意: 若在该类中加上一个缺省构造函数,而此时编译不会自动生成一个合成的默认构造函数,但是会在该类中本来有的构造函数中加上一些东西:
//         在生成对象时:
//             假设该类继承了基类,则会在其中安插代码:目的是调用基类的构造函数;
//             假设该类中有虚函数时,也会在其中安插代码:目的是生成虚函数表,以及把虚函数表地址赋给类对象的虚函数表指针;
//         ==>当有自己的构造函数时,编译器会根据需要扩充构造函数
//         ==>编译器干了很多事,有构造函数时,根据需要扩充构造函数,无构造函数时,需要情况下合成构造构造函数

4.如果一个类带有虚基类,编译器也会为他合成一个默认构造函数.
    虚基类:通过两个直接基类继承同一个间接基类.(三层结构:爷爷Grand,两个爹A,A2,一个孙子C)
    对于虚基类结构,编译器为子类和父类都产生了合成默认构造函数

*/
#include <iostream>
using namespace std;

class Grand//爷爷类
{
  public:
};

class A : virtual public Grand//爹类
{
  public:
};

class A2 : virtual public Grand//爹类
{
  public:
};

class C : public A,public A2//孙子类
{
  public:
};


int main(int, char**) 
{


    C cc;

    //输出:
    // 无任何输出,但是保存my.txtx后可以搜索到A,A2,C合成的默认构造函数:
    //  产生了vbtable(虚基类表)

    return 1;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值