C++ 静态数据成员与静态成员函数
C 静态数据成员与静态成员函数1. 概述在 C 中使用static关键字修饰的类数据成员或成员函数称为静态数据成员和静态成员函数。它们与类本身关联而非与类的某个具体对象关联。静态成员在整个程序运行期间只有一份副本被所有类对象共享。2. 静态数据成员2.1 定义与初始化静态数据成员必须在类内声明在类外文件作用域定义并初始化除静态常量整型成员外。定义时不需要重复static关键字但需要加上类名和作用域运算符::。// CountedObject.h#ifndefCOUNTED_OBJECT_H#defineCOUNTED_OBJECT_HclassCountedObject{public:CountedObject();~CountedObject();staticintGetCount();// 静态成员函数声明private:staticintcount_;// 静态数据成员声明引用性声明};#endif// CountedObject.cpp#includeCountedObject.h// 静态数据成员定义性声明在文件作用域初始化intCountedObject::count_100;CountedObject::CountedObject(){count_;}CountedObject::~CountedObject(){--count_;}intCountedObject::GetCount(){returncount_;}2.2 访问方式通过类名加作用域运算符CountedObject::GetCount()通过对象或对象指针co1.GetCount()或co2-GetCount()不推荐易混淆2.3 特点与注意事项静态数据成员独立于任何对象存在即使没有创建类对象它也已分配内存。所有对象共享同一个静态数据成员。静态数据成员可以是private通过公有静态成员函数访问实现封装。静态数据成员的名字位于类作用域中避免与全局变量冲突。3. 静态成员函数3.1 特点静态成员函数没有this指针因此不能直接访问非静态数据成员或调用非静态成员函数。非静态成员函数可以任意访问静态数据成员和静态成员函数。静态成员函数只能访问静态数据成员和其他静态成员函数。3.2 示例错误与正确访问#includeiostreamusingnamespacestd;classTest{public:Test(inty):y_(y){}voidNonStaticFun(){cout非静态函数中访问静态成员 x_ x_endl;StaticFun();// 非静态成员函数可以调用静态成员函数}staticvoidStaticFun(){// NonStaticFun(); // 错误静态成员函数不能调用非静态成员函数// cout y_; // 错误不能访问非静态成员cout静态函数中访问静态成员 x_ x_endl;}private:staticintx_;// 静态数据成员声明inty_;};// 静态数据成员定义及初始化intTest::x_100;intmain(){Testt(10);t.NonStaticFun();// 输出非静态函数中访问静态成员 x_ 100Test::StaticFun();// 输出静态函数中访问静态成员 x_ 100// 通过对象访问静态成员允许但不推荐coutt.x_endl;// 100coutTest::x_endl;// 推荐方式return0;}4. 静态常量数据成员static const修饰的静态常量成员其值不可修改。对于整型int、char、bool等静态常量成员可以在类内直接初始化C11 以后也允许非整型但推荐统一在类外定义。示例#includeiostreamusingnamespacestd;classTestConst{public:staticconstintkValue100;// 静态常量整型可在类内初始化staticconstdoublekPi;// 非整型只能在类外定义};// 静态常量成员类外定义不带 static 关键字constdoubleTestConst::kPi3.14159;intmain(){coutTestConst::kValueendl;// 100coutTestConst::kPiendl;// 3.14159// TestConst::kValue 200; // 错误常量不可修改return0;}5. 综合示例统计对象个数以下是一个完整的、可运行的统计某类对象创建与销毁个数的程序。// CountedObject.h#ifndefCOUNTED_OBJECT_H#defineCOUNTED_OBJECT_HclassCountedObject{public:CountedObject();~CountedObject();staticintGetCount();private:staticintcount_;};#endif// CountedObject.cpp#includeCountedObject.hintCountedObject::count_0;CountedObject::CountedObject(){count_;}CountedObject::~CountedObject(){--count_;}intCountedObject::GetCount(){returncount_;}// main.cpp#includeCountedObject.h#includeiostreamusingnamespacestd;intmain(){cout初始对象数: CountedObject::GetCount()endl;// 0CountedObject obj1;CountedObject obj2;cout创建两个对象后: CountedObject::GetCount()endl;// 2CountedObject*pObjnewCountedObject;cout动态创建一个对象后: CountedObject::GetCount()endl;// 3deletepObj;cout删除动态对象后: CountedObject::GetCount()endl;// 2return0;}6. 重点总结特性静态数据成员非静态数据成员存储位置全局数据区独立于对象每个对象各自的内存空间初始化类外定义时初始化仅一次构造函数初始化列表或体内访问方式类名::成员或 对象.成员只能通过对象或指针访问能否被静态成员函数访问可以不可以能否被非静态成员函数访问可以可以特性静态成员函数非静态成员函数是否含有this指针否是能否访问静态成员可以可以能否访问非静态成员不可以可以调用方式类名::函数名或 对象.函数名必须通过对象或指针调用7. 常见误区与注意事项静态成员函数不能调用非静态成员函数因为非静态成员函数隐含this指针而静态函数没有。静态数据成员不能在类内初始化除static const整型外必须在类外单独定义。通过对象访问静态成员容易产生误解建议使用类名::静态成员以明确其属于类。静态成员变量即使不创建任何类对象也已存在并可通过类名访问如果为public。