lesson3-C++类和对象(下)(一)+https://developer.aliyun.com/article/1393914
概念
- 声明为static的类成员称为类的静态成员。
- 用static修饰的成员变量,称之为静态成员变量;
- 用static修饰的成员函数,称之为静态成员函数。
- 静态成员变量一定要在类外进行初始化。
实现一个类,计算程序中创建出了多少个类对象。
class A { public: A() { _count++; } A(const A& a) { _count++; } static int Get_count() { return _count; } private: static int _count; }; //这里才是_count的定义 int A::_count = 0; void func(A a) { //... } int main() { A a; A b(a); func(a); cout << A::Get_count() << endl; return 0; }
结果为3。
特性
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区,所以在使用时要加作用域限定符,比如:A::Get_count()
- 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明,比如:int A::_count = 0;
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员.
- 静态成员也是类的成员,受public、protected、private 访问限定符的限制
友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以
友元不宜多用。
友元分为:友元函数和友元类
友元函数
我们现在可以去尝试重载operator<<运算符重载了。
如果我们将这个重载写在类体内,那么必然会有this指针去占到参数的第一个位置,那么我们再调用cout时流插入流入的方向就变成流向对象了,看例子:
#include <iostream> using namespace std; class Date { public: Date(int year = 2023, int month = 11, int day = 2) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "_" << _day << endl; } ostream& operator<<(ostream& out) { out << _year << "-" << _month << "-" << _day; return out; } private: int _year; int _month; int _day; }; int main() { Date a; a << cout; }
这样重载<<运算符是不是很别扭,非常奇怪,所以注定了我们要将他重载到类外,也就是全局,
那么我们将其写在全局后,又因为这几个成员变量都是私有的,我们在类外无法访问到,我们当然可以写他们的Get函数得到他们的值,但是这样比较麻烦,而且C++不喜欢这样做,java才喜欢,C++会去搞一个友元函数。
直接看用法。
#include <iostream> using namespace std; class Date { //在函数前加friend表示是友元函数,虽然我们将其声明在类内,但这个函数不属于类 friend ostream& operator<<(ostream& out, const Date& d); public: Date(int year = 2023, int month = 11, int day = 2) { _year = year; _month = month; _day = day; } void print() { cout << _year << "-" << _month << "_" << _day << endl; } private: int _year; int _month; int _day; }; ostream& operator<<(ostream& out, const Date& d) { out << d._year << "-" << d._month << "_" << d._day << endl; return out; } int main() { Date a; cout << a; }
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在
类的内部声明,声明时需要加friend关键字。
这样我们重载的函数成为了Date类的友元函数,就可以访问Date私有的成员变量。
友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
我们举例说明,看代码:
#include <iostream> using namespace std; class Date { friend class Time; public: Date(int year = 2023, int month = 11, int day = 2) { _year = year; _month = month; _day = day; } void print() const { cout << _year << "-" << _month << "_" << _day << endl; } private: int _year; int _month; int _day; }; class Time { public: Time(int hour = 11, int minute = 54, int second = 0) :_hour(hour) ,_minute(minute) ,_second(second) {} void Print_Date_Time() const { cout << _d._year << "-" << _d._month << "-" << _d._day; cout << ":"; //cout << _hour << "-" << _minute << "-" << _second << endl; printf("%d-%d-%02d\n", _hour, _minute, _second); } private: int _hour; int _minute; int _second; Date _d; }; int main() { Time t; t.Print_Date_Time(); }
我们要注意Time是Date的友元,Time可以访问Date的私有的成员变量,但是Date不能访问Time私有的成员变量,有句话说的好,我把你当朋友,但是你不一定把我当朋友,就是这个道理。
内部类
首先说明C++中很少使用内部类,java是喜欢使用内部类的,我们只需要明白他的语法,能够看懂,明白需要注意的地方就好,很少使用内部类。
#include <iostream> using namespace std; class A { public: A() { _count++; } A(const A& a) { _count++; } static int Get_count() { return _count; } class B { public: B() { _count++; _a = 3; } private: int _a; }; private: int _A; static int _count; }; int A::_count = 0; int main() { cout << sizeof(A) << endl; return 0; }
我们可以看到计算A的大小时不包括B,可以这么理解,B是一个独立的类,只是受到A的访问限定符的限制,并且B天生就是A的友元,可以访问A的私有变量。
两个点:
- A,B是独立的两个类,只是B受到A访问限定符的限制。
- B天生就是A的友元。
其余不再多说。
lesson3-C++类和对象(下)(三)+https://developer.aliyun.com/article/1393918