C++幕后故事(二)--编译器合成默认的构造函数

编译器合成缺省(无参)的构造函数

1.先考虑一个问题为什么c++中有构造函数?

这个可以从语言设计的角度来看这个问题。体现一个实例化的对象生命周期的完整性,一个对象在初始化的时候,让使用者有机会做些额外的初始化操作。同样,一个对象是消亡的时候,也要使用者有机会去释放资源。举个例子:吃饭前先洗手(构造函数),吃完饭在擦嘴(析构函数),这是个好习惯。但是你不洗手,不擦嘴,也没关系,只是这不是个好习惯而已(偶尔造成细菌感染,程序异常)。

2.编译器何时合成缺省构造函数?

好习惯的养成是一个持续的过程,所以有时候编译器会偷偷的帮你洗手擦嘴。

A.间接的含有构造函数,比如类成员变量含有构造函数,或者是继承的父类有构造函数。

B.直接或者间接的含有virtual function,比如自己含有virtual function或者是类成员变量,或者是继承的父类含有。

C.出现虚继承的现象。

3.那么构造函数的兄弟拷贝构造?

拷贝构造和缺省的构造也是同样的A,B,C情况下,编译器会合成默认的拷贝构造。当然编译器生成的拷贝构造就是浅拷贝。

4.那么析构函数呢?

编译器不关心你有没有写析构函数,编译器都会主动生成析构函数。在析构的时候,编译会首先调用你写的析构函数,然后在调用编译器的析构函数,这个过程对于程序员来说是透明的。从反汇编的角度看,编译器会生成一个析构函数,但是这个析构函数没有实质作用,也没有生成汇编代码

// 没有析构函数的类
class NoDctorClass
{
public:
    int m_a;
};

// 测试编译器合成析构函数
void test_compiler_geneator_def_dctor()
{
    NoDctorClass no_dctor_class;
    // 调用析构函数
    no_dctor_class.~NoDctorClass();
    no_dctor_class.m_a = 0;
}
// 转到反汇编的代码
//    NoDctorClass no_dctor_class;
//    调用析构函数,这里没有生成任何的反汇编代码
//    no_dctor_class.~NoDctorClass();
//    no_dctor_class.m_a = 0;
012AA9FE  mov         dword ptr [no_dctor_class],0  

5.那么编译器为什么帮你合成(拷贝)构造函数?

简单一句话,编译器需要插入一些额外的初始化代码,来完成一些语言特性。

A.间接的含有缺省构造函数,这时候编译器发现你自己没有写构造函数,但是你又间接含有构造函数。编译器这时候有两种做法,一种是心想算了吧我帮你偷偷的生成一个吧,还有一种做法就是编译器报语法错,让程序员自己解决。所以编译器厂商一商量觉得还是对程序员友好一点,用第一种做法吧。反过来想,如果一门开发语言对程序员不友好,可以说是它的生存期将会非常短。

B.直接或者间接的含有virtual function,因为含有virtual function,为了支持多态的特性,那么每个实例对象都会生成指向虚函数表的指针。但是这个指针在什么时候初始化呢?自然是(拷贝)构造函数里面。但是你自己没有写,编译器只好累一点生成(拷贝)构造函数。

C.虚继承情况,为了避免子类中含有多余的成员变量,对象在实例化的时候会生成指向虚基类表的指针。自然就会联想到在(拷贝)构造函数的时候生成,同样你自己没有写,编译器管家来替你写。

6.如何验证编译器合成了(拷贝)构造函数?

1.在你的菜单栏找到如下控制台

2.cd到编译生成目录下,找到你生成的obj文件,比如我生成main.obj。

3.执行 dumpbin.exe /all main.obj >> main.txt,将文件格式翻译为COFF。

 4.查看main.txt 找到,如果所示找到1所对应的函数,下面的2就是编译器准备插入的代码,可以看到插入了MatrixA的构造函数。同理,可以验证其他的情况。

7.知道编译器在何时合成构造函数那么又怎么样?

1.知道编译器背着我们做了那些小动作,让我们可以更加了解这门语言背后实现的细节,做到胸中自有丘壑。

2.尽量不要依赖编译器的操作。

3.要站在编译器的角度去看问题。

8.总结:

构造函数和拷贝构造是你的左膀右臂,建议还是得要好好的利用。尽管有时候你不承认,但是编译器这个管家还是会偷偷摸摸的给你装个左膀右臂。如果说构造函数是你的左膀右臂,那么析构函数就是你的一把强有力的武器用于保护自己,在对象生命结束之后能够确保资源的正常释放。

9.代码示例:

/****************************************************************************
**
** Copyright (C) 2019 635672377@qq.com
** All rights reserved.
**
****************************************************************************/

/*
    测试编译器在何种情况会合成默认的构造函数
    同理可证:在何种情况下编译器会合成默认的拷贝构造函数
*/

#ifndef default_constrcuctor_h
#define default_constrcuctor_h

#include <iostream>

using std::cout;
using std::endl;

namespace defualt_constructor
{

// 含有缺省的构造函数成员类对象
// #define has_default_ctor_member 1

// 继承含有缺省的构造函数
// #define has_inherit_ctor_base 1

// 含有虚函数成员函数
// #define has_virtual_function 1

// 函数virtual函数的成员类对象
// #define has_virtual_func_member 1

// 父类含有虚函数
// #define has_inherit_virtual_func_base 1

// MatrixC, MatrixB 虚继承MatrixD
// #define has_virtual_inherit_base 1

// 类成员变量含有copy ctor
// #define has_default_copy_ctor_member 1

// 父类含有拷贝构造函数
#define has_inherit_copy_ctor_base 1

// 含有虚函数成员函数
// #define has_virtual_function_copy_ctor 1

// 类对象成员含有虚函数
// #define has_virtual_function_copy_ctor_member 1

// 父类函数虚函数
// #define has_inherit_virtual_function_copy_ctor_base 1

// 虚继承copy ctor
// #define has_virtual_inherit_function_copy_ctor_base 1

class MatrixD
{
};

#ifdef  has_virtual_inherit_base
class MatrixC : virtual public MatrixD
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixC : virtual public MatrixD
#else
class MatrixC
#endif // has_virtual_inherit_base
{
public: 
#ifdef has_inherit_ctor_base
    MatrixC() { cout << "MatrixC" << endl; }
#elif has_inherit_copy_ctor_base
    MatrixC() {}
    MatrixC(const MatrixC &rhs) { cout << "MatrixC copy ctor" << endl; }
#elif has_inherit_virtual_function_copy_ctor_base
    virtual void VirFun() {}
#elif has_inherit_virtual_func_base
    virtual void VirFun() {}
#endif // has_virtual_inherit_base
};

#ifdef has_virtual_inherit_base
class MatrixB : virtual public MatrixD
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixB : virtual public MatrixD
#else
class MatrixB
#endif // has_virtual_inherit_base
{
public:
#ifdef has_default_ctor_member
    MatrixB() { cout << "MatrixB" << endl; }
#elif has_virtual_func_member
    virtual void VirMatrixB() { cout << "virtual MatrixB" << endl; }
#elif has_default_copy_ctor_member
    MatrixB() {}
    MatrixB(const MatrixB &rhs) { cout << "copy ctor MatrixB" << endl; }
#elif has_virtual_function_copy_ctor_member
    virtual void VirMatrixB() { cout << "virtual MatrixB" << endl; }
#endif // has_default_ctor_member

    int m_high;
    int m_width;
};

#ifdef has_default_ctor_member
class MatrixA
#elif has_virtual_function
class MatrixA
#elif has_inherit_ctor_base
class MatrixA : public MatrixC
#elif has_inherit_copy_ctor_base
class MatrixA : public MatrixC
#elif has_virtual_func_member
class MatrixA
#elif has_virtual_inherit_base
class MatrixA : public MatrixB, public MatrixC
#elif has_inherit_virtual_func_base 
class MatrixA: public MatrixC
#elif has_inherit_virtual_function_copy_ctor_base
class MatrixA : public MatrixC
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixA : public MatrixB, public MatrixC
#else
class MatrixA
#endif // has_default_ctor_member
{
public:
    int m_age;
    int m_score;

#ifdef has_default_ctor_member
    MatrixB matrixB;
#elif has_virtual_function
    virtual void VirFunc() { cout << "virtual function" << endl; }
#elif has_virtual_func_member
    MatrixB matrixB;
#elif has_default_copy_ctor_member
    MatrixA() {}
    MatrixB matrixB;
#elif has_inherit_copy_ctor_base
    MatrixA() {}
#elif has_virtual_function_copy_ctor
    virtual void VirFunc() { cout << "virtual function" << endl; }
#elif has_virtual_function_copy_ctor_member
    MatrixB matrixB;
#endif // has_default_ctor_member

};

void test_compiler_generator_def_ctor()
{
    //用dumpbin把.obj文件内容导出成可查看文件my.txt,
    // 这个my.txt格式,一般被认为是COFF:通用对象文件格式(Common Object File Format);

    MatrixA matrix;
    matrix.m_age = 0;

    // 编译器会在哪些情况下合成默认的构造函数?
    // 1.包含一个类成员变量,此成员变量含有默认的缺省构造函数。此时编译器就会
    // 生成默认的构造函数。在这个合成的构造函数中插入代码调用成员变量的构造函数
    // 2.继承的父类含有缺省的构造函数,此时编译器也会构造默认的构造函数,在子类合成的构造
    // 函数中插入代码,调用父类的缺省构造
    // 3.包含虚函数。不管是子类,父类,还是包含的成员类对象(不包含任何构造函数),只要
    // 包含了virtual function,编译器都会合成默认的构造函数
    // 4.含有虚继承现象,grandfather, parent(虚继承grand),child再继承,
    // 为了在构造函数中生成vbtable,虚基类表

    // 同样的道理,copy constrcutor也和constructor也是在同样的情况下,编译器会合成默认
    // 的构造函数

    // A.含有默认的构造函数
    //  1.父类有默认的构造函数
    //  2.包含类对象的成员变量含有默认构造函数

    // B.虚函数
    //  1.不管是自己包含虚函数,还是类成员变量有虚函数,还是父类中虚函数

    // C.虚继承
    //  1.编译器为了在插入vbtable 虚基类表
}

void test_compiler_generator_def_copy_ctor()
{
    MatrixA ma;

    MatrixA mb = ma;
    // 编译器合成默认copy ctor时机和ctor是一样的
}

}

#endif // default_constrctor_h

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值