初始化列表:
class date { public: date(int year = 1,int month = 1,int day = 1) :_year(year), _month(month)//这里就是初始化列表和括号里面的作用是一样的 { _day = day; } private: int _year; int _month; int _day; }; int main() { date d1; }
我们知道我们的类里面的成员变量只是变量的声明,然后我们可以认为初始化列表就是我们对象成员变量定义的地方。
我们初始化列表主要是为了那些必须在定义的是初始化的变量准备的:这里的 d1 是对象定义的地方,那我们的成员变量在哪里定义呢,所以就有了初始化列表
大家看如果我不给那些特殊的变量在初始化列表定义会发什么:
class date { public: date(int year = 1, int month = 1, int day = 1,int tmp = 5,int ret=10) :_year(year), _month(month) /*_tmp(tmp), _ret(ret)*/ { _day = day; } private: int _year; int _month; int _day; const int _tmp; int& _ret; }; int main() { date d1; }
这里就直接报错了,当然这些特殊的变量是不能在括号里面通过赋值来完成操作的:
date(int year = 1, int month = 1, int day = 1,int tmp = 5,int ret=10) :_year(year), _month(month) { _day = day; _tmp = tmp; _ret = ret; }
特殊的成员变量还包括那些需要构造函数需要传参的自定义类型:
class aa { public: aa(int i) :_a(i) {} private: int _a; }; class date { public: date(int year = 1, int month = 1, int day = 1,int tmp = 5,int ret=10) :_year(year), _month(month), _tmp(tmp), _ret(ret), _a(1) { _day = day; } private: int _year; int _month; int _day; const int _tmp; int& _ret; aa _a; };
在看这样的代码:
class aa { public: aa(int i = 0) :_a(i) {} private: int _a; }; class date { public: date(int year = 1, int month = 1, int day = 1,int tmp = 5,int ret=10) :_year(year), _month(month), _tmp(tmp), _ret(ret), { _day = day; } private: int _year; int _month; int _day; const int _tmp; int& _ret; aa _a; };
我们没有在初始化列表里面写自定义类型的定义,它会调用自定义类型的构造函数嘛?
肯定是会的,我们这里只是没有显示的去初始化,但它依旧会去调用的,调用的地方依旧也是初始化列表
总结:其他的变量可以在初始化列表初始化,也可以在函数体内初始化,建议尽量在初始化列表初始化
在定义的地方赋值不是初始化 这个是给缺省值,缺省值也是给我们的的初始化列表使用的,要是显示地初始化就用显示地
1. private: 2. int _year = 1; 3. int _month = 2; 4. int _day = 3;
顺序?
初始化列表里面也是有执行的顺序的,这个顺序是由变量声明的顺序决定的
class date { public: date(int year = 1, int month = 1, int day = 1,int tmp = 5,int ret=10) :_month(month), _year(year), _tmp(tmp), _ret(ret), { _day = day; } private: int _year; int _month; int _day; const int _tmp; int& _ret; aa _a; };
看这里就是 _year->_month->_day 的顺序
explicit关键字:
我们知道不同类型的变量变量赋值是会发生隐式类型的转换的,那给自定义类型赋值会不会发生隐式转换呢?
date d1 = 2013;
这里是会发生隐式类型的转换的,我们的 整型转换成自定义类型 调用构造函数,紧接着就是拷贝构造了,但是由于编译器优化的原因,这里是直接调用构造函数的,注意我们调用构造函数产生的是一个临时变量(具有常性)
但如果加上explicit关键词,就会报错了,这个关键词意思就是不让进行隐式转换:
静态成员:
class date { public: private: static int _year; static int _month; static int _day; };
大家觉得这个类的大小是多少呢?
答案是 1 ,我们的静态成员是属于整个类的,是属于所有类的所有对象,是属于静态区的,他也不是在初始化列表里面初始化。我们多个对象访问这个静态变量都是访问的一个变量
class date { public: private: static int _year; static int _month; static int _day; }; int date::_year = 2012; int date::_month = 8; int date::_day = 1;
上面这个是初始化的方式,注意是一定得再外面初始化,不能在声明那里赋值,像非静态成员变量那样给缺省值,这样是不行的
cout << date::_year << endl;
我们可以这样去访问,但是前提是你的成员得是共有的才可以。
成员函数也是可以设为静态的,静态的成员函数就没有this指针,同样也是可以通过类域去访问这个函数的
注意:我们静态的成员函数是不能访问静态的成员的。大家知道为什么吗
因为我们的静态成员函数没有this指针,没有this指针怎么去访问呢,大家说是不是
友元类:
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
class tmp { public: tmp(int hour, int min, int sec) :_hour(hour), _min(min), _sec(sec) { } private: int _hour; int _min; int _sec; }; class date { public: void print() { cout << tt._hour << '-' << tt._min << '-' << tt._sec << endl; } private: int _year; int _month; int _day; tmp tt; };
大家看这里我们的打印是会报错的,报的就是这个成员是私有无法访问,像这种情况加个友元类就可以了
class tmp { friend class date; public: tmp(int hour, int min, int sec) :_hour(hour), _min(min), _sec(sec) { } private: int _hour; int _min; int _sec; }; class date { public: void print() { cout << tt._hour << '-' << tt._min << '-' << tt._sec << endl; } private: int _year; int _month; int _day; tmp tt; };
这样就相当于告诉我们的tmp: date是它的朋友,可以访问它的私有成员,注意:友元的关系是单向的,友元关系不能传递,假如A是B的友元,然后B是C的友元,这样不能说A是C的友元
一个函数也可以是多个类的友元(写得时候要注意我们的类是向上找的)
内部类:
内部类,顾名思义就是内部定义的一个类,首先这个内部的类是默认为它外面那个类的友元类的。
class date { public: date(int year = 1, int month = 1, int day = 1) :_year(year), _month(month), _day(day) {} class tmp { public: tmp(int hour, int min, int sec) :_hour(hour), _min(min), _sec(sec) { } void print(const date& test) { cout << test._year << '-' << test._month << '-' << test._day << endl; } private: int _hour; int _min; int _sec; }; private: int _year; int _month; int _day; };
那大家觉得我们去计算这个类的大小会是多大呢,这个计算需要包括内部类的大小嘛?
答案是不用的,我们计算的依旧只是成员变量的大小(除了static修饰的不计算)
还有一个点要注意:我们的内部类是可以直接访问外部类的static成员的,不需要加类名和对象名
匿名对象?
class tmp { public: void print() { cout << _hour << '-' << _min << '-' << _sec << endl; } private: int _hour; int _min; int _sec; }; int main() { tmp()//这就是一个匿名对象,它的声明周期只存在在这一行,过了这一行它就会自动销毁 }
那我们的匿名对象有什么作用嘛?
当我们想要调用一个类里面的一个函数,我们可能会这样做:
1. tmp d1; 2. d1.print();
但有了匿名对象后就可以这样:
tmp d1().print();