前言
初始化列表是书写构造函数的一种方式,某些成员变量之只能通过初始化列表进行初始化。另外学习c++不可避免地需要知道什么样的变量存储在什么区域当中如栈,堆,静态区,常量区
初始化列表
书写格式
书写上,初始化列表,以冒号开始,以逗号分割的数据成员列表,每个成员变量后面个呢一个放在括号后面的初始值或表达式
如下图所示给出一个日期类的初始化列表
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}private:int _year;int _month;int _day;
};
初始化列表有什么作用
1.初始化列表可以代替大部分函数体内赋值
2.某些成员变量只能通过初始化列表初始化
引用成员变量,const成员变量,自定义类型变量(且该类没有构造函数时)只能在初始化列表中初始化
一些需要注意的点
1.每个成员变量在初始化列表只能出现一次,不能重复定义
2.成员声明的位置和初始化列表中变量的位置顺序相同,因为初始化列表是根据成员定义时的位置一一初始化的
class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print(){cout<<_a1<<" "<<_a2<<endl;}
private:int _a2;int _a1;
}int main()
{A aa(1);aa.Print();
}
这个例子就能很好的体现上述问题,定义的顺序和初始化列表的顺序不同,所以a1在拷贝构造给a2时还没有初始化,所以打印出来的应该是1和随机值
3.初始化列表和函数体内赋值各有优略,比如函数体内赋值可以对malloc进行检查等等
4.当我们使用初始化列表初始化自定义成员时,如果自定义成员的构造函数没有缺省值,需要显式传参
静态成员
区块的分类
这里所说的分类都是虚拟内存,分为栈区,堆区,静态区(数据段),代码段(常量区)
静态成员变量
静态成员变量在类中声明时,需要在最开头加上static关键字,静态成员变量不能够在类内初始化,只能通过访问限定符在类外初始化
静态成员变量存放在静态区
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}static int sign;
private:int _year;int _month;int _day;};
int Date::sign = 1;
静态成员变量依然收到private等关键字的限制,定义在public中可以用域限定符或者访问操作符访问
所有统一个类的对象共用一个静态成员变量
不能用初始化列表来初始化静态成员变量,定义只能在类外进行定义,使用域限定符
静态成员函数
静态成员函数和静态成员变量很像,所有同一个类的对象共用,受private关键字限制
静态成员函数没有this指针,意味着它不能够调用非静态成员变量
我们一般喜欢使用静态成员函数去调用静态成员变量,配套使用
友元
友元有许多种,但是归根结底友元的目的是让私有的成员也能让其他非成员的函数或者类访问
比如
#include <iostream>
using namespace std;
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}friend ostream& operator<<(ostream& out,Date& d);static int sign;
private:int _year;int _month;int _day;};
int Date::sign = 1;
ostream& operator<<(ostream& out,Date& d)
{out<<d._year<<" "<<d._month<<" "<<d._day;return out;
}int main()
{Date d1(2025,8,5);cout<<d1<<endl;cout<<d1.sign;
}
这样一个流运算符的重载就只能写成友元函数,因为他一定有一个ostream对象占用一个参数,而我们又希望他能够输出结果,那就只能使用友元了。
书写的方法很简单,只需要在类内声明这个函数,并在最前方加上friend关键字即可
内部类天然是外部类的友元
类内可以定义内部类,内部类可以访问外部类的所有成员,但是外部类无法访问内部类的私有成员
注意:私有内部类受访问限定符的限制