深挖构造函数
构造函数的实现有两种,一种是普通的函数实现(详细的讲解在我上一篇博客:https://blog.csdn.net/2501_94265972/article/details/163389995?spm=1011.2124.3001.6209):
#include<iostream>
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;
}
其中无参和全缺省构造函数同时存在会产生歧义。
构造函数初始化还有另一种方式,就是初始化列表,使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
#include<iostream>
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 成员变量、没有默认构造函数的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错。
所以尽量使用初始化列表进行初始化,因为在编译器初始化变量时,会先执行初始化列表,然后执行构造函数函数体。和默认构造函数一样,如果不显式写初始化列表,它也是存在的,但内容为空。
如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显式在初始化列表初始化的内置类型成员是否初始化取决于编译器,一般情况下只是一个垃圾值。比如:
#include<iostream>
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;
}
这一段代码中,在类中的声明中给了缺省值,且没有显式写构造函数,这时候默认生成的初始化列表就会用缺省值初始化:
对于没有显式在初始化列表初始化的
自定义类型成员
会调用这个成员类型的默认构造函数,如果没有默认构造函数会编译错误。
初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。我们先看一段代码:
#include<iostream>
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。这就是结果
网硕互联帮助中心




评论前必须登录!
注册