当前位置: 首页 > news >正文

【C++】深入解析构造函数初始化

1. 再谈构造函数

1.1 构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值

class Date
{ 
public: Date(int year, int month, int day) {     _year = year;     _month = month;      _day = day; } 
private: int _year; int _month; int _day; 
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值

1.2 初始化列表

在构造函数的地方进行初始化

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。

class Date 
{ 
public: Date(int year, int month, int day): _year(year) , _month(month) , _day(day) {} 
private: int _year; int _month; int _day; 
};

【注意】

1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

  • 引用成员变量

  • const 成员变量

  • 自定义类型成员(且该类没有默认构造函数时)

class A 
{ 
public:  A(int a) :_a(a) {} 
private:  int _a; 
}; class B 
{ 
public:  B(int a, int ref) :_aobj(a) ,_ref(ref) ,_n(10) {} 
private:  A _aobj;  // 没有默认构造函数  int& _ref;  // 引用  const int _n; // const  
};

3.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化

class Time 
{ 
public:  Time(int hour = 0) :_hour(hour) {  cout << "Time()" << endl; } 
private:int _hour; 
}; 
class Date 
{ 
public:  Date(int day) {} 
private: int _day;  Time _t; 
}; int main() 
{     Date d(1); 
}

4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关,即初始化时会先初始化_a2,再初始化_a1

class A 
{ 
public:     A(int a) :_a1(a) ,_a2(_a1) {}      void Print() {         cout<<_a1<<" "<<_a2<<endl; } private:     int _a2;     int _a1; 
}; int main() {     A aa(1);     aa.Print(); 
} 
A. 输出1  1 
B.程序崩溃 
C.编译不通过 
D.输出1  随机值
答案:D

1.3 explicit 关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。‘

class Date 
{ 
public:
// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用  
// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译  explicit Date(int year) :_year(year) {}  
/*  
// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具 
有类型转换作用  
// explicit修饰构造函数,禁止类型转换  
explicit Date(int year, int month = 1, int day = 1)  : _year(year)  , _month(month)  , _day(day)  {}  
*/ Date& operator=(const Date& d) {  if (this != &d) {  _year = d._year;  _month = d._month;  _day = d._day; } // return *this; } 
private:  int _year;  int _month;  int _day; 
}; void Test() 
{  Date d1(2022);  // 用一个整形变量给日期类型对象赋值  // 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值  d1 = 2023;  // 将1屏蔽掉,放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转换的作用 
}

上述代码可读性不是很好,用 explicit 修饰构造函数,将会禁止构造函数的隐式转换

隐式类型转换:

// 单参数构造函数(未用explicit修饰时)
Date(int year) : _year(year) {}

当执行 d1 = 2023 时,编译器会自动进行以下隐式转换:

用 2023 作为参数,隐式构造一个临时的 Date 对象(等价于 Date(2023))调用赋值运算符 operator=,将这个临时对象赋值给 d1

http://www.dtcms.com/a/354310.html

相关文章:

  • Docker 镜像重命名【打上新的标签】
  • AI应用图文解说--百度智能云实现语音聊天
  • Python爬虫获取1688商品列表与图片信息
  • 【免驱】一款基于AI8H2K08U芯片的USB转RS485模块,嵌入式工程师调试好帮手!
  • Web 自动化测试常用函数实战(一)
  • 如何防御安全标识符 (SID) 历史记录注入
  • 嵌入式学习day38
  • 怎样选择合适的报表系统?报表系统的主要功能有什么
  • PLC_博图系列☞基本指令”S_PULSE:分配脉冲定时器参数并启动“
  • PyTorch闪电入门:张量操作与自动微分实战
  • Wxml2Canvas在组件中的渲染获取不到元素问题
  • vue 海康视频插件
  • Java Spring Boot 集成淘宝 SDK:实现稳定可靠的商品信息查询服务
  • AI鱼塘,有你画的鱼吗?
  • 代码随想录刷题Day44
  • IDEA连接阿里云服务器中的Docker
  • 嵌入式学习日志————DMA直接存储器存取
  • 微信开发者工具中模拟调试现场扫描小程序二维码功能
  • Centos 7.6离线安装docker
  • 元宇宙+RWA:2025年虚拟资产与真实世界的金融融合实验
  • aiohttp模块如何使用
  • 开发避坑指南(39):Java List全null元素引发的空判断无效处理方案
  • 用LightRAG打造智能问答系统:知识图谱与RAG的融合应用实践
  • 如何在升级到S/4HANA后关闭SAP旧系统?
  • 3-4〔OSCP ◈ 研记〕❘ WEB应用攻击▸Burp Suite工具
  • MySQL中的InnoDB
  • pikachu-xss通关(1-8)
  • qt5+mingw64+opencv4.5.2搭建调试环境
  • FOC算法第二节 克拉克变换
  • mybatis-plus实现苍穹外卖项目-分类操作,不定期更新-day2