1.0构造函数是什么?
构造函数是一个特别的类成员函数,特别在函数名与类名相同。
2.0构造函数存在的意义?
为了在类对象实例化的同时对类成员变量初始化(在类成员函数的初始化列表)。
代码一
#include<iostream>
using namespace std;
class Day
{
public:
//Day(int year, int month, int day) :_year(year), _month(month), _day(day)//初始化列表,冒号开始逗号隔开
//{
//}
private:
int _year;
int _month;
int _day;
};
int main()
{
Day day;
system("pause");
return 0;
}
汇编代码如下:
再看一段代码做一比较
代码二:
#include<iostream>
using namespace std;
class Day
{
public:
Day()
{}
private:
int _year;
int _month;
int _day;
};
int main()
{
Day day;
system("pause");
return 0;
}
分析:代码一没有显式默认构造函数(Day(){})所以编译器自动构造出这个构造函数(只是用来给类成员变量初始化),
代码二可以看到直接对显式默认构造函数进行调用,并对类成员变量初始化。
两个的初始化都为随机值。
将类对象的成员变量初始化为确定值有一下方法:
代码三:
#include<iostream>
using namespace std;
class Day
{
public:
Day(int year, int month, int day) :_year(year), _month(month), _day(day)
{}
private:
int _year;
int _month;
int _day;
};
int main()
{
Day day(2017, 10, 26);
system("pause");
return 0;
}
汇编代码如下
这种方法是在构构造函数声明后面的初始化列表(以一个冒号开始,接着是一个以逗号分隔的数据成
员列表,每个数据成员后面跟一个放在园括号中的初始化式)中初始化
员列表,每个数据成员后面跟一个放在园括号中的初始化式)中初始化
方法二:
即为在构造函数中将构造函数的参数一次赋值给类成员变量。
按照方法一初始化时需要注意:尽量按照类成员变量定义的顺序初始化,尽量避免使用成员初始化成员,
成员的初始化顺序最好和成,否则会初始化错误。
例如:
代码四
#include<iostream>
using namespace std;
class Day
{
public:
Day(int year, int month, int day) :_year(year), _month(_day), _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Day day(2017, 10, 26);
system("pause");
return 0;
}
Day内容:
第二个month就不能以期望的结果输出
代码五:
#include<iostream>
using namespace std;
class Day
{
public:
Day(int year, int month, int day) :_year(year), _month(_day), _day(day)
{
cout << this << endl;
}
private:
int _year;
int _month;
int _day;
};
void FunTest()
{
Day day(2017, 10, 26);
}
int main()
{
FunTest();
system("pause");
return 0;
}
代码六:
#include<iostream>
using namespace std;
class Day
{
public:
Day()
{}
Day(int year, int month, int day) :_year(year), _month(month), _day(day)
{
cout << this << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Day day(2017, 10, 26);
system("pause");
return 0;
}
以上代码可以说明构造函数可以重载。
代码七:
#include<iostream> using namespace std; class Day { public: Day(int x) { } Day(int year, int month, int day) :_year(year), _month(_day), _day(day) { } private: int _year; int _month; int _day; }; int main() { Day a = 10;//相当于Day(10); system("pause"); return 0; }
以上代码说明了构造函数的参数自动转换为类对象
explicit: 在Day(int x)前面加上explicit代码就会发生一下结果
无法从10转换成Day型
代码八
#include<iostream>
using namespace std;
class Time
{
public:
friend class Day;
Time(int hour, int minute, int second)
{
_hour=hour;
_minute=minute;
_second=second;
}
Time(const Time& d)
: _hour(d._hour)
, _minute(d._minute)
, _second(d._second)
{}
private:
int _hour;
int _minute;
int _second;
};
class Day
{
public:
Day(int year, int month, int day) :_year(year), _month(month), _day(day), _t(year,month,day)
{
cout << _year << "-" << _month << "-" << _day << "-"<<_t._hour<<"-"<<_t._minute<<"-"<<_t._second<< endl;
}
/*Day(const Day& d)
: _year(d._year)
, _month(d._month)
, _day(d._day)
{}*/
private:
int _year;
int _month;
int _day;
Time _t;
};
int main()
{
Day(2017, 10, 28);
system("pause");
return 0;
}
代码八说明了下面的情况3.0
类中包含以下成员必须要放在初始化列表中初始化:
1.0常量成员,因为常量成员只能初始化不能赋值,所以必须放在初始化列表里。
2.0引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表。
3.0没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数来初始化。
类中包含以下成员必须要放在初始化列表中初始化:
1.0常量成员,因为常量成员只能初始化不能赋值,所以必须放在初始化列表里。
2.0引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表。
3.0没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数来初始化。
代码九(为以上情况1和2实例)
#include <iostream>
using namespace std;
class A
{
public:
A(int &v) : i(v), p(v), j(v) {
cout << i << " " << j << endl;
}
private:
const int i;//类成员为const类型
int p;
int &j;//类成员为引用类型
};
int main()
{
int a = 21;
A b(a);
system("pause");
return 0;
}
最后再做一总结
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对
象时,由编译器自动调用,在对象的生命周期内只调用一次,保
证每个数据成员都有一个合适的初始值。
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对
象时,由编译器自动调用,在对象的生命周期内只调用一次,保
证每个数据成员都有一个合适的初始值。
类中包含以下成员必须要放在初始化列表中初始化:
1、引用数据成员
2、const数据成员
3、类类型成员(有构造函数,但不是缺省的构造函数) 【默认构造函数】
类如果没有显式定义构造函数时,编译器会合成一个默认的构造函数,该构造函数中什么工作都不做。只要显式定义了,即使该构造函数什么也不做,编译器也不会为该类合成默认的构造函数。编译器生成的默认构造函数使用与成员变量初始化相同的规则来初始化成员,具有类类型的成员通过运行各自的默认构造函数来进行初始化。内置和复合类型的成员如指针、数组,只对定义在全局作用域中的对象初始化,当对象定义在局部作用域时,内置和符合类型的成员不进行初始化。在某些情况下,默认构造函数是由编译器隐式使用的。
【explicit】
用explicit修饰构造函数,抑制由构造函数定义的隐式转换,
explicit关键字类内部的构建声明上,在类的定义体外部的定义上
不再重复。
1、引用数据成员
2、const数据成员
3、类类型成员(有构造函数,但不是缺省的构造函数) 【默认构造函数】
类如果没有显式定义构造函数时,编译器会合成一个默认的构造函数,该构造函数中什么工作都不做。只要显式定义了,即使该构造函数什么也不做,编译器也不会为该类合成默认的构造函数。编译器生成的默认构造函数使用与成员变量初始化相同的规则来初始化成员,具有类类型的成员通过运行各自的默认构造函数来进行初始化。内置和复合类型的成员如指针、数组,只对定义在全局作用域中的对象初始化,当对象定义在局部作用域时,内置和符合类型的成员不进行初始化。在某些情况下,默认构造函数是由编译器隐式使用的。
【explicit】
用explicit修饰构造函数,抑制由构造函数定义的隐式转换,
explicit关键字类内部的构建声明上,在类的定义体外部的定义上
不再重复。
【构造函数特性】
1、函数名与类名相同。
2、没有返回值。
3、有初始化列表(可以不用)。
4、新对象被创建,由编译器自动调用,且在对象的生命期内仅
调用一次。
5、构造函数可以重载,实参决定了调用那个构造函数。
6、如果没有显式定义时,编译器会提供一个默认的构造函数。
7、无参构造函数和带有缺省值得构造函数都认为是缺省构造函
数,并且缺省构造函数只
能有一个。
1、函数名与类名相同。
2、没有返回值。
3、有初始化列表(可以不用)。
4、新对象被创建,由编译器自动调用,且在对象的生命期内仅
调用一次。
5、构造函数可以重载,实参决定了调用那个构造函数。
6、如果没有显式定义时,编译器会提供一个默认的构造函数。
7、无参构造函数和带有缺省值得构造函数都认为是缺省构造函
数,并且缺省构造函数只
能有一个。
构造函数作用:
1、构建对象
2、初始化对象
3、类型转换
【构造函数作用:构造和初始化对象】
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成
员列表,每个数据
成员后面跟一个放在园括号中的初始化式。
1、构建对象
2、初始化对象
3、类型转换
【构造函数作用:构造和初始化对象】
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成
员列表,每个数据
成员后面跟一个放在园括号中的初始化式。
【注意】
1、每个成员在初始化列表中只能出现一次(为什么)
2、初始化列表仅用于初始化类的数据成员,并不指定这些数据成员的初始化顺序,数据成员在类中定义顺序就是在参数列表中的初始化顺序。
3、尽量避免使用成员初始化成员,成员的初始化顺序最好和成成员的定义顺序保持一致。
1、每个成员在初始化列表中只能出现一次(为什么)
2、初始化列表仅用于初始化类的数据成员,并不指定这些数据成员的初始化顺序,数据成员在类中定义顺序就是在参数列表中的初始化顺序。
3、尽量避免使用成员初始化成员,成员的初始化顺序最好和成成员的定义顺序保持一致。