摘要:初始化列表,explicit关键字,匿名对象,static成员,友元,内部类,编译器优化
类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性、哪些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。
构造函数函数体内是对成员变量进行赋值,而不是初始化!
初始化列表:成员变量定义的地方
对于以下三类特殊的成员变量类型,初始化列表的存在是必要的:
warning:Initialization is not assignment. Initialization happens when a variable is given a value when it is created. Assignement obliterates an object's current value and replaces that value with a new one.
Four different ways to define an int variable named units_sold and initialize it to 0:
- int units_sold = 0;
- int units_sold = {0}; //list initialization (C++11)
- int units_solc{ 0 }; //list initialization (C++11)
- int units_sold(0);
——《C++ Primer》
sum.能用初始化列表就用初始化列表,但同时有些场景需要初始化列表和构造函数体混用。(根据具体的需求而异)
补充:C++11 支持在成员变量声明的时候给缺省值,这个缺省值是给初始化列表用的,如果初始化列表没有显式给初始值,就用缺省值作为初始化值。
在构造函数前加 explicit 使得不能进行隐式类型转换:(示例如下)
- class B
- {
- public:
- explicit B(const int b1, const int b2)
- {
- _b1 = b1;
- _b2 = b2;
- }
- explicit B(const B& b)
- {
- _b1 = b._b1;
- _b2 = b._b2;
- }
- private:
- int _b1;
- int _b2;
- };
用途:
const引用其实使得匿名对象变成了有名对象:引用给了匿名对象别名,这个“别名”的生命周期即为被引用的匿名对象的生命周期。e.g.const A& ref = A();
如果我们有如下两个需求:
统计累计创建的对象:首先,我们可以选择创建全局变量来统计。同时,因为创建对象会自动调用构造函数,所以我们在构造函数体内对这个用于统计的变量进行++操作,这样每次创建一个对象,就会调用并执行构造函数,每次执行都会累计对这个全局变量++。
统计正在使用的对象:对象销毁会自动调用析构函数,创建的对象 - 已经析构的对象 = 正在使用的对象。
- int e = 0;//统计累计创建的对象
- int now_e = 0;//统计仍在使用的对象
-
- class A
- {
- public:
- A(const int a = 0)
- {
- ++e;
- ++now_e;
- _a = a;
- }
- ~A()
- {
- --now_e;
- }
- private:
- int _a;
- };
问题:不够封装,全局变量可能会被随意修改,将造成需求之外的影响。 → “封装” → 将变量放入类中 → 私有变量无法访问 → static 成员
static 成员变量的性质:
static 成员变量的声明与定义:类内声明,类外定义(静态成员变量一定要在类外进行初始化)
- class A
- {
- private:
- static int m;//static成员变量声明
- };//这样写A相当于空类
-
- int A::m = 0;//static成员变量定义
访问 static 成员变量的两种情况下的方式:
- class A
- {
- public:
- static int m;//static成员变量声明
- };//这样写A相当于空类
-
- int A::m = 0;//static成员变量定义
-
- int main()
- {
- A aa;
- aa.m;//①创建对象访问;
-
- A* p = nullptr;
- p->m;//②通过指针访问
-
- A::m = 1;//③直接访问
- return 0;
- }
- class A
- {
- public:
- int GetM()
- {
- return m;
- }
- private:
- static int m;//static成员变量声明
- };
-
- int A::m = 0;//static成员变量定义
-
- int main()
- {
- A aa;
- cout << aa.GetM() << endl;
- return 0;
- }
static 成员函数的性质:
特性:
- class Date
- {
-
- friend ostream& operator<<(ostream& out, Date d);//友元函数声明
-
- private:
- int _year;
- int _month;
- int _day;
- };
-
-
- ostream& operator<<(ostream& out, Date d)//函数定义
- {
- out << d._year << "/" << d._month << "/" << d._day << endl;
- return out;
- }
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。(如下代码,B类在A类友元声明之后,B类中的所有成员函数相当于在A类中都进行了友元声明——可以访问A类的非公有成员。注意:A类不可以访问B类的非公有成员。)
友元类的性质:
①单向性(如下,B可以访问A,但A不可以访问B);
②友元关系不传递(B是A的友元,A是C的友元,不能得出B是C的友元);
③不继承。
- class A
- {
- friend class B;
-
- private:
- int _a;
- };
-
-
-
- class B
- {
- void Print(A _aa)
- {
- cout<<_aa._a;
- }
-
- //A aa;//注意:这个只是声明,不开空间
- };
内部类:在类中再定义一个类。内部类仅受外部类的类域和访问限定符限制,此外内部类与外部类是两个独立的类。
使用场景:内部类可以应用于当你想定义一个类而仅在某个类中使用时。
注意:如上图,C不可以访问D的非公有成员, D在C类域之内又封装了一层,并且根据友元类的单向性也是如此。
此部分内容仅作了解,在之前旧版本的博客有较为详细的讲述,详细内容可参见本文:C++ -4- 类和对象(下)
END