2.static
知识点:
概念:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化,此处他并不是每个类对象的成员变量,而是每个对象共享的一个变量
语法:在变量/函数前面加上static
初始化需要再类外面进行,具体如下:
class A { public: A(int a)//并且不能在构造中初始化 { } private: int _a; static int _b;//声明 }; int A::_b = 0;//初始化 int main() { return 0; }
不能在类内部定义
细节:
为了防止我们可以随意的更改_b , 所以一般会把_b放到私有里面。
此时就只能通过在类里面创建一个获取函数/创建友元函数来 获取里面的_b了
对于获取函数来说,我们也一般习惯写成静态的,当把函数也写成静态的时候,此时这个函数时没有this指针的,就只能通过通类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
。
static int GetB()//一般我们会把这个定义成静态的函数,此时是没有this指针的,指定类域和访问限定符就能进行访问该函数
static int GetB()//一般我们会把这个定义成静态的函数,此时是没有this指针的,指定类域和访问限定符就能进行访问该函数 { return _b; } //访问: //cout << a.GetB() << endl; cout << A::GetB() << endl;
注意,因为在静态函数中没有this指针,所以不能去调用成员变量/成员函数,而在成员函数中却可以去调用静态的函数,如果一定需要去使用成员函数,则需要传进来,并且需要在参数部分接收
类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
静态成员也是类的成员,受public、protected、private 访问限定符的限制
练习:
设计一个类,在类外面只能在栈上创建对象
设计一个类,在类外面只能在堆上创建对象
class A { public: static A GetStack() { A a; return a;//返回创建的对象 } static A* GetHeap() { return new A;//new一个空间给A } private: A() {} private: int _a = 0; int _b = 1; }; int main() { //此时没有别的办法就只能用静态函数 //因为构造函数也属于私有的,所以我们不能直接定义一个对象 A::GetStack(); A::GetHeap(); return 0; }
3.友元
知识点:
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度(关联性),破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类
细节:
3.1友元函数
在前面的 operator <<、operator >> 处我们已经使用过了,是用来让函数可以使用一个类中的成员变量
语法:friend 函数声明
友元函数可以访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
友元函数不能用const修饰(因为其没有this指针)
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
3.2友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
(和友元函数一样,当我们在一个类中定义了另外一个友元的类对象,此时在另外的那个类中就能去使用声明的类中的成员变量)
具体写法:friend class 类名
练习使用:
class B { friend class A; private: int _b = 10; }; class A { public: A() {} void Print() { //此时创建一个B类的对象就能去访问其类内的私有 cout << _i._b << endl; } private: int _a = 0; B _i; }; int main() { A a; a.Print(); return 0; }
4.内部类
知识点:
一个类定义在另一个类的内部,这个内部类就叫做内部类
细节:
内部类是外部类的友元类,所以说在内部类可以使用外部类的成员变量,但是外部类却不能使用内部类的成员变量,所以说我们可以直接把,内部类的成员变量写在外部,这样就能一起使用了。
内部类同样是受public、protected、private访问限定符的限制,当写成私有时类外面也无法直接使用
练习使用:
还有写许细节已经进行了注释
class A { public: class B {//此时的B就是A的一个内部类,并且内部类时外部类的友元,可以使用外部类的变量 public: B() {} void Print(const A& a)//注意也并不是直接就能使用其成员变量,还是需要先实例化一个对象的 { cout << a._a << a._b << endl; } private: }; private: int _a = 0; int _b = 10; }; int main() { A a; A::B b;//当是public 时就能在外部定义了 return 0; }
class A { public: class B {//此时的B就是A的一个内部类,并且内部类时外部类的友元,可以使用外部类的变量 public: B() { } void Print() { cout << _a <<_b << endl;//此处对于静态成员来说直接通过A::xxx 就能访问,所以对在A类内的B就能直接使用静态的 } private: }; private: static int _a; static int _b; }; int main() { A a; A::B b;//当是public 时就能在外部定义了 return 0; }
5.匿名对象
知识点:
匿名对象,其是就是创建一个没有对象名的对象,并且此时匿名对象在创建行构造,到下一行时就会析构。
匿名对象的创建方法: 类名 ();
匿名对象的使用方法:类名() . 调用的函数;
细节:
匿名对象和临时变量一样都具有常性,所以要引用这个对象的话需要加上const来修饰
如const A& ra = A();
并且对于被引用的匿名对象来说,他的生命周期也会因为被引用而延长到该局部函数结束时
附:在创建对象的时候不能写成 如 Date d(); 因为此时编译器无法分清这是函数的声明还是你对象的构造,所以对于不传参的情况不用加上括号
具体练习:
class A { public: A(int a = 0) :_a(a) { cout << "A(int a)" << endl; } ~A() { cout << "~A()" << endl; } private: int _a; }; class Solution { public: int Sum_Solution(int n) { //... return n; } }; int main() { A aa1;//正常的构造 A();//匿名对象,生命周期在本行 A aa2(2);//正常的构造 Solution().Sum_Solution(10);//匿名对象调用其函数,并且此处并不会调用构造函数 const A& ra = A();//注意匿名对象具有常性,所以需要在引用前面+const A aa3(3);//正常的构造 return 0; }
本章完。预知后事如何,暂听下回分解。