C++构造函数深度解析:从基础实现到初始化列表的奥秘
深挖构造函数构造函数的实现有两种一种是普通的函数实现详细的讲解在我上一篇博客https://blog.csdn.net/2501_94265972/article/details/163389995?spm1011.2124.3001.6209#includeiostream using namespace std; class Date { public: // 1. 无参构造函数 Date() { _year 1; _month 1; _day 1; } // 2. 带参构造函数 Date(int year, int month, int day) { _year year; _month month; _day day; } // 3. 全缺省构造函数 // Date(int year 1, int month 1, int day 1) // { // _year year; // _month month; // _day day; // } void Print() { cout _year / _month / _day endl; } private: int _year; int _month; int _day; }; int main() { Date d1; // 调用默认构造函数 d1.Print(); return 0; }其中无参和全缺省构造函数同时存在会产生歧义。构造函数初始化还有另一种方式就是初始化列表使用方式是以一个冒号开始接着是一个以逗号分隔的数据成员列表每个成员变量后面跟一个放在括号中的初始值或表达式。#includeiostream using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) :_year(year) , _month(month) , _day(day) { } void Print() { cout _year / _month / _day endl; } private: int _year; int _month; int _day; }; int main() { Date d1; // 调用默认构造函数 d1.Print(); return 0; }我们运行一下可以看到 d1 成功初始化了列表中的缺省值。那么为什么要有两种方法C 规定引用成员变量、const 成员变量、没有默认构造函数的类类型变量必须放在初始化列表位置进行初始化否则会编译报错。所以尽量使用初始化列表进行初始化因为在编译器初始化变量时会先执行初始化列表然后执行构造函数函数体。和默认构造函数一样如果不显式写初始化列表它也是存在的但内容为空。如果这个成员在声明位置给了缺省值初始化列表会用这个缺省值初始化。如果你没有给缺省值对于没有显式在初始化列表初始化的内置类型成员是否初始化取决于编译器一般情况下只是一个垃圾值。比如#includeiostream using namespace std; class Date { public: void Print() const { cout _year / _month / _day endl; } private: int _year 1; int _month 1; int _day 1; }; int main() { Date d1; // 调用默认构造函数 d1.Print(); return 0; }这一段代码中在类中的声明中给了缺省值且没有显式写构造函数这时候默认生成的初始化列表就会用缺省值初始化对于没有显式在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数如果没有默认构造函数会编译错误。初始化列表中按照成员变量在类中声明顺序进行初始化跟成员在初始化列表出现的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。我们先看一段代码#includeiostream using namespace std; class A { public: A(int a) :_a1(a) , _a2(_a1) {} void Print() { cout _a1 _a2 endl; } private: int _a2 2; int _a1 2; }; int main() { A aa(1); aa.Print(); }可能会有很多人认为这段代码的运行结果是1 1但实际上是是1和一个垃圾值因为初始化的顺序是类中声明的顺序所以先对_a2初始化然而初始化列表中有对_a1的初始化所以编译器会忽视缺省值从而_a1给_a2的是一个随机值所以_a2是一个随机值然后对_a1初始化形参a为1所以_a1为1。这就是结果