3.构造函数

引入

  • 要创建一个对象,需要进行两步操作
    • 为该对象分配一块内存
    • 调用该对象的构造函数,对这块内存进行初始化操作
  • 所以构造函数时创建对象的基础

默认构造函数

  • 不需要参数、或者为所有参数都提供了默认实参的构造函数,都可以被称为默认构造函数
  • 一个类可以拥有多个默认构造函数,但此时也就意味着不能通过默认构造函数构造该对象
    class message
    {
    public:
        message() {}
        message(std::string msg = "") {}
    };
    int main()
    {
    
        message msg_1;	//error 重载message()调用不明显
    
        message msg_2("");	//能成功匹配 message(std::string);
        
        return 0;
    }
    

合成构造函数

  • 当一个类没有显示定义默认构造函数,且这个类需要默认构造函数,那么编译器将为其合成一个默认构造函数;如下面这个类

    class message
    {
    
    private:
        std::string msg;
    };
    
    int main()
    {
        message msg;
        return 0;
    }
    

    其汇编代码如下,只截取重要部分

    不懂汇编也没关系,只要知道汇编中的call等价函数调用即可

    	main:
    		......
    		leaq	-32(%rbp), %rax
    		movq	%rax, %rcx
    		call	_ZN7messageC1Ev			#调用构造函数
    		movl	$0, %ebx
    		leaq	-32(%rbp), %rax
    		movq	%rax, %rcx
    		call	_ZN7messageD1Ev			#调用析构函数
    		movl	%ebx, %eax
    		addq	$72, %rsp
    		......
    

    asm高亮不出来,将就看一下

  • 在以下几种情况,编译器认为这个类需要有默认构造函数(前置条件是程序中使用了隐式构造的方式构造这个类1

    • 含有类对象成员,且该类具有非合成默认构造函数

      类对象成员的初始化需要调用构造函数,如果这个类没有实现默认构造函数,编译器将为其合成,且在初始化列表调用其类成员对象的默认构造函数

    • 派生自定义了非合成默认构造函数的基类

      继承中,基类的构造部分需要放在初始值列表中,如果其基类具有默认构造,且这个派生类没有实现默认构造,编译器将为其合成,且在合成的构造函数初始化列表中调用其基类的默认构造函数

    • 类中具有虚函数

      存在虚函数就需要初始化虚指针,而虚指针则是在构造函数体前进行隐式初始化,所以编译器需要为其合成默认构造函数

    • 继承链中具有虚继承
  • 可以将= default显示让编译器合成默认构造函数

  • 合成的构造函数不会初始化基本内置类型

初始化列表

class message
{
    message() : initialize_list
    {
    }
};
  • 只有在初始化列表中的操作才能算初始化,而在构造函数中进行的是初始化之后的操作,所以类常量成员只能在初始化列表中进行初始化赋值
  • 初始化列表只指定初始化对象的值,其初始化顺序与在类中定义的顺序一致

委托构造

  • 在初始化列表中调用自身的其他构造函数,将产生委托构造
  • 在完成被委托构造函数的初始化列表2和函数体后,将回到委托调用处
  • 初始值列表中只能存在一个委托构造

转换构造函数

  • 如果一个构造函数,可以只支持一个参数,那么实际上也就定义了将其他类型转换为该类类型的机制
    class message
    {
    public:
        message(int data_) : data(data_) {}
    
    private:
        int data;
    };
    
    int main()
    {
        message msg = 1;
        return 0;
    }
    
  • 默认其支持隐式转换,使用explicit关键字修饰后,其只支持显示转换
    class message
    {
    public:
        explicit message(int data_) : data(data_) {}
    
    private:
        int data;
    };
    
    int main()
    {
        message msg_1 = 1;	//erro 不能将int转化为message
    
        message msg_2 = static_cast<message>(1);
        return 0;
    }
    
  • 对于隐式转换,编译器只会进行一步转换3

结语

  • 构造函数内容不好线性总结,写的比较混乱
  • 本文只涉及一些基础内容
  • 有任何错误评论区指正,共同进步

  1. 在构造对象时,如果调用默认构造函数时加上(),将导致编译器将这条语句识别为函数声明;而不使用()的方式,就被称为隐式构造 ↩︎

  2. 这就意味着如果两个构造函数相互委托,将导致死锁,直到栈满,程序结束 ↩︎

  3. A --> B可直接完成,B --> C可以直接完成,A --> C不能直接完成(除非实现了A到C的转换) ↩︎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值