C++的Static关键字
一、静态成员
在类定义中,它的成员(包括成员变量和成员函数),这些成员可以用关键字static声明为静态的,称为静态成员。
不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。
例如 :定义一个Person内含静态成员sNum,sOther
/** * 定义一个Person内含静态成员sNum,sOther */ class Person{ public: //类的静态成员属性 static int sNum; private: static int sOther; };
二、静态成员变量
由一我们知道,静态成员变量,属于某个类,所有对象共享。
静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。
***注意:
(1)静态成员变量必须在类中声明,在类外定义。
(2)静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间。
(3)静态数据成员可以通过类名或者对象名来引用。
例如:还是在刚才的接口中我们定义类和 初始化静态成员。为了研究静态成员的访问,我们将其设为public,方便设计实验。
我们可以看到类外初始化,初始化时不加static
#include <iostream> using namespace std; /** * 定义一个Person内含静态成员sNum,sOther */ class Person{ public: //类的静态成员属性 static int sNum; private: static int sOther; }; //只能类外初始化,初始化时不加static int Person::sNum = 0; int Person::sOther = 0;
例如在实现cpp文件中
#include "../header/Person.h" int main(){ //1. 通过类名直接访问 Person::sNum = 100; cout << "Person::sNum:" << Person::sNum << endl; //2. 通过对象访问 Person p1, p2; p1.sNum = 200; cout << "p1.sNum:" << p1.sNum << endl; cout << "p2.sNum:" << p2.sNum << endl; //3. 静态成员也有访问权限,类外不能访问私有成员 //cout << "Person::sOther:" << Person::sOther << endl; Person p3; //cout << "p3.sOther:" << p3.sOther << endl; system("pause"); return EXIT_SUCCESS; }
cout << "Person::sOther:" << Person::sOther << endl;
cout << "p3.sOther:" << p3.sOther << endl;
静态成员也有访问权限,类外不能访问私有成员,所以上面语句报错。
执行结果如下:
三、静态成员函数
在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是,不能访问普通成员变量。
静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。
(1)静态成员函数只能访问静态变量,不能访问普通成员变量
(2)静态成员函数的使用和静态成员变量一样
(3)静态成员函数也有访问权限
(4)普通成员函数可访问静态成员变量、也可以访问非经常成员变量
例如:在接口中定义一个Person内含静态成员sNum,mParam为普通变量
/** * 定义一个Person内含静态成员sNum,mParam为普通变量 */ class Person{ public: //普通成员函数可以访问static和non-static成员属性 void changeParam1(int param){ mParam = param; sNum = param; } //静态成员函数只能访问static成员属性 static void changeParam2(int param){ //mParam = param; //无法访问 sNum = param; } private: static void changeParam3(int param){ //mParam = param; //无法访问 sNum = param; } public: int mParam; static int sNum; }; //静态成员属性类外初始化 int Person::sNum = 0;
在实现中:
#include "../header/Person.h" int main(){ //1. 类名直接调用 Person::changeParam2(100); //2. 通过对象调用 Person p; p.changeParam2(200); //3. 静态成员函数也有访问权限 //Person::changeParam3(100); //类外无法访问私有静态成员函数 //Person p1; //p1.changeParam3(200); return EXIT_SUCCESS; }
四、const静态成员属性
如果一个类的成员,既要实现共享,又要实现不可改变,那就用 static const 修饰。定义静态const数据成员时,最好在类内部初始化
#include <iostream> using namespace std; /** * 定义一个静态常数据成员mShare,并且先在类中定义好 */ class Person{ public: //static const顺序可交换 //static const int mShare = 10; const static int mShare = 10; //只读区,不可修改 }; int main(){ cout << "Person::mShare : " << Person::mShare << endl; //Person::mShare = 20;报错,不能再外部定义 return EXIT_SUCCESS; }
执行结果:
五、静态成员实现单例模式
单例模式是一种我平时java开发中常用的设计模式。
在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法(工厂factory设计模式),让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
例如:可以使用函数打印要输出的内容,并且可以累积函数使用次数。
#include <iostream> using namespace std; /** * 定义Printer类 */ class Printer{ public: static Printer* getInstance(){ return pPrinter;} /** * 内部定义一个public类,用于打印内容text,并记录打印的次数 * @param text */ void PrintText(string text){ mTimes++; cout << "打印内容:" << text << endl; cout << "已打印次数:" << mTimes << endl; cout << "--------------" << endl; } private: //默认构造函数和拷贝构造函数设计为私有 Printer(){ mTimes = 0; } Printer(const Printer&){} private: static Printer* pPrinter; int mTimes; }; Printer* Printer::pPrinter = new Printer; /** * 测试类,测试PrintText方法。 */ void test() { Printer* printer = Printer::getInstance(); printer->PrintText("内容1"); printer->PrintText("内容2"); printer->PrintText("内容3"); } int main(){ test(); return EXIT_SUCCESS; }
执行结果: