1.初始化列表:
1.1为什么要有初始化列表?
实验代码如下:
class A { public: int _a1;//声明 int _a2; const int _x; }; int main() { A aa;//定义 return 0; }
❓有一个const成员函数时,定义对象会报错
📚 原因: const变量必须在定义的地方初始化
❓对象在main函数内定义,而对象中的成员变量在哪里初始化呢?
📚 可以使用缺省值 const int _x=1;//缺省值,可以过
因此我们需要考虑有const的情况,我们要想办法初始化成员变量
1.2初始化列表的写法:
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟
一个放在括号中的初始值或表达式。
class A { public: A() : _a2(1) ,_x(1) { _a1++; _a2--; } private: int _a1=1;//声明 int _a2=2; const int _x=1;//缺省值,可以过 };
哪个对象调用构造函数,初始化列表都是它所有成员变量初始化的位置
不管是否显示在初始化列表写,那么编译器每个变量都会初始化列表定义初始化
【注意】
每个成员变量在初始化列表中只能出现一次**(初始化只能初始化一次**)
类中包含以下成员,必须放在初始化列表位置进行初始化:
- 引用成员变量
- const成员变量
- 自定义类型成员(且该类没有默认构造函数时))
1.2.1如果成员变量有自定义类型的话:
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化
class B { public: B(int b) :_b(0) { cout << "B()" << endl; } private: int _b; }; class A { public: A() :_x(1) , _a2(1) , _ref(_a1) , _bb(0)//如果没有默认构造函数,就相当于调用它的构造函数 { _a1++; _a2--; } private: int _a1=1;//声明 int _a2=2; const int _x=1;//缺省值,可以过 int& _ref; B _bb;//默认构造函数,对于内置类型不处理,对于自定义类型会调用默认构造 //对于自定义类型,如果没写,会去调用默认构造, };
因为默认构造函数,对于内置类型不处理,对于自定义类型会调用默认构造
所以当成员列表中有自定义类型,如果没写构造函数,会去调用默认构造
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
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(); } A. 输出1 1 B.程序崩溃 C.编译不通过 D.输出1 随机值
选D
2.explicit关键字:
📚构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值构造函数,还具有类型转换的作用。**
class Date { public: explicit Date(int year) :_year(year) {} /*explicit Date(int year, int month = 1, int day = 1) : _year(year) , _month(month) , _day(day) {}*/ Date& operator=(const Date& d) { if (this != &d) { _year = d._year; _month = d._month; _day = d._day; } return *this; } private: int _year; int _month; int _day; }; void Test() { Date d1(2022); d1 = 2023; } int main() { Test(); return 0; }
💡 说明:
如果有explicit,第30行会编译失败,explicit修饰构造函数后,禁止了单参构造函数的类型转换(这里的类型转换是2023转换成了Date类型)
实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
如果使用多参数的构造函数,也是同样的原理。
3.static成员:
📚 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化
3.1static特性:
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区,静态成员的字节大小不算在sizeof内
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; class Test { private: static int _n; int a; }; int main() { cout << sizeof(Test) << endl; return 0; }
静态成员在sizeof中是否被计算?
只有在类和结构体位置才会被忽略,其他方面正常计算
静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
class Test { public: private: static int _n; //静态成员的声明 int a; }; int Test::_n = 10;
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> class Test { public: static void Fun() { std::cout << _a << std::endl; //不能访问非静态成员 std::cout << _b << std::endl; } private: int _a; static int _b; };
- 静态成员也是类的成员,受public、protected、private 访问限定符的限制
❓【问题】
- 静态成员函数可以调用非静态成员函数吗?
- 非静态成员函数可以调用类的静态成员函数吗?
💡 说明:
1.没有this指针调用不了
2.OK