目录
1.初始化列表
初始化与赋值
缺省值
2.隐式类型转换
单参数的隐式类型转换
多参数的隐式类型转换
3.explicit关键字
4.类中的静态成员
1.初始化列表
基本语法:
using namespace std;
class Date
{
public:Date(int year, int month, int day)//以下就是初始化列表:_year(year), _month(month), _day(day){};
private:int _year;int _month;int _day;
};
初始列表的本质:就是每个对象中成员定义的地方。
初始化列表的一些特点:
1.const修饰的成员变量必须在初始化列表上定义(因为const修饰的变量必须在定义的时候初始化)
2.引用(引用与const类似,必须在定义的时候初始化)
3.没有默认构造的自定义类型的成员变量必须显示传参。
以下有个例子
//A没有默认构造
class A
{
public:A(int a){_a = a;}
private:int _a;
};class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day),_a(0)//A没有默认构造,所以这里需要显示传参{};
private:int _year;int _month;int _day;A _a;
};
这里说一下什么是默认构造?有三大类,编译器自动生成的,无参的和全缺省的
4.初始化列表的初始化顺序与初始化列表写的初始化的顺序无关,与声明的顺序一致。
初始化与赋值
初始化
class Date
{
public:Date(int year, int month, int day)//以下是初始化:_year(year), _month(month),_day(day){};
private:int _year;int _month;int _day;
};
赋值
class Date
{
public:Date(int year, int month, int day){//以下是赋值_year = year;_month = month;_day = day;};
private:int _year;int _month;int _day;
};
虽然上面两个代码的效果一样,但往往第一个效率更高。
建议尽量在初始化列表的时候初始化完成员变量。
缺省值
class A
{
public:A(int a){_a = a;}void Print(){cout << _a << endl;}
private:int _a;
};class Date
{
public:Date(){};void Print(){cout << _year << " " << _month << " " << _day << endl;_a.Print();}
private://给缺省值int _year = 10;int _month = 10;int _day = 10;A _a = 1;
};
缺省值是用于初始列表的,如果给了那么初始列表中就可以不显示写该变量的初始化。
初始化列表无论你写不写,每个成员都会走一遍,内置类型有缺省值的用缺省值,没有缺省值的C++没有规定对其做不做处理,有的编译器会做处理,有的编译器不会做处理;自定义类型调用其默认构造,如果没有默认构造就需要在初始化列表中显示传参,否则编译器会报错。
2.隐式类型转换
单参数的隐式类型转换
内置类型转换为自定义类型时会发生。
该类型转换发生的条件:内置类型中应该有合适的构造函数
class A
{
public:A(int a){_a = a;}void Print(){cout << _a << endl;}
private:int _a;
};int main()
{A a = 1;//这里发生了隐式类型转换有int转换成了自定义类型 Aa.Print();return 0;
}
A& a = 1;//将1转换成A类型的引用是否可以呢?
答案是不可以,那么时为什么呢?
int类型的变量会通过构造形成一个A类型的临时变量,而临时变量具有常性,但是a是这个临时变量的引用,存在权限放大问题。
那么如何解决这个问题呢?
const A& a = 1;//用const修饰就可以了,这样就权限平移了
多参数的隐式类型转换
class B
{
public:B(int a, int b){_a = a;_b = b;}
private:int _a;int _b;
};
int main()
{B b = { 1,2 };//多参数的隐式类型转换return 0;
}
相较于单参数的隐式类型转换,多参数的转换需要用花括号。
3.explicit关键字
用途:这个关键字的作用就是禁止隐式类型转换。
使用:
class A
{
public:explicit A(int a)//在隐式类型转换是需要调用的构造函数前加explicit就可以了{_a = a;}void Print()const{cout << _a << endl;}
private:int _a;
};int main()
{A& a = 1;a.Print();return 0;
}
禁用后,如果还使用隐式类型转换就会报错。
4.类中的静态成员
静态成员变量的初始化
class A
{
private:int _a;static int tmp;//静态成员变量
};
注意静态成员变量不能给缺省值,因为缺省值都是在给初始化列表的。而静态成员变量的初始化不走初始化列表。
那么静态成员变量该如何初始化呢?
得在类外初始化:
class A
{
private:int _a;static int tmp;//静态成员变量
};int A:: tmp = 1;//初始化
当然有个例外:比如容器vector中npos就可以直接用缺省值初始化。
template<class T>
class vector
{//.....const static size_t npos = -1;
};
静态成员变量属于该类的所有对象,并且该类在计算大小时计入静态成员的大小。
静态成员函数
class A
{
public:static void Print(){cout << _a << endl;//错误静态成员函数不能访问成员变量cout << tmp << endl;//正确可以访问静态成员变量}
private:int _a;static int tmp;//静态成员变量
};
为什么静态成员函数不能访问非静态成员变量?
因为静态成员函数中的参数没有隐藏的this指针,所以访问不到相应的对象的成员变量,但可以访问静态的成员变量。