C++中static关键字在类中的使用需要注意一些细节。static 在类中修饰的是数据成员及成员函数,分别称为静态数据成员及静态成员函数。
static数据成员及static成员函数
先来看看static静态数据成员的目的及使用:
(1)、对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量。比如说统计某种类型对象已创建的数量。
(2)、如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量。这时我们可以用类的静态成员来解决这个问题。
(3)、非静态数据成员存在于类类型的每个对象中,静态数据成员则独立于该类的任意对象而存在,它是与类关联,不与类对象关联。
static静态数据成员的优点:
(1)、static静态数据成员的名字是在类的作用域中,因此可以避免与其它类成员或全局对象名字冲突。
(2)、可以实施封装,static静态数据成员可以是私有的。
(3)、阅读程序容易看出static成员与某个类相关联,这种可见性可以清晰的反映程序员的意图。
static成员函数需要注意的事项:
(1)、static成员函数没有this指针,因为它是与类关联的,不与对象关联。
(2)、非静态成员函数可以访问静态成员。
(3)、静态成员函数不可以访问非静态成员。
static静态数据成员及静态成员函数的使用方法。
先来看看下面的统计对象个数类的定义。
CountedObject.h
#ifndef _COUNTED_OBJECT_H
#define _COUNTED_OBJECT_H
class CountedObject
{
public:
CountedObject();
~CountedObject();
public:
static int GetCount(); //静态成员函数
private:
static int count_; // 静态数据成员在定义时有两步:1 静态成员的引用性声明 2 在文件域上进行定义性说明。 这里只是第一步
};
#endif
统计对象类的实现,CountedObject.cpp
#include "CountedObject.h"
int CountedObject::count_ = 100; //静态数据成员定义性声明方法:1 需要加上类名域运算符 2不需要static关键字 3 只能在文件作用域中进行初始化,不能在类中进行初始化
CountedObject::CountedObject()
{
++count_; //创建对象时自加
}
CountedObject::~CountedObject()
{
--count_; //销毁对象时自减
}
//静态成员函数在定义时不加static修饰,只能访问静态数据成员,不能访问普通数据成员
int CountedObject::GetCount()
{
return count_;
}
下面是对静态数据成员及静态成员函数的访问例子:
main.cpp
#include "CountedObject.h"
#include <iostream>
using namespace std;
int main()
{
//cout << CountedObject::count_ << endl; //静态数据成员可以用类名来访问,如果是私有的则不能访问了,只能提供一个公有接口来访问
cout << CountedObject::GetCount() << endl; //output:100
CountedObject co1;
cout << CountedObject::GetCount() << endl; //output:101
CountedObject *co2 = new CountedObject;
cout << CountedObject::GetCount() << endl; //output:102
delete co2;
cout << CountedObject::GetCount() << endl; //output:101
return 0;
}
static静态常量数据成员
首先,静态处理数据成员它属于静态的数据成员,与静态数据成员不同的是,它的值是const ,不能被修改。并且静态常量数据成员也是与类关联的,全体所有对象共享。普通成员函数及静态成员函数均可以访问它。
#include <iostream>
using namespace std;
class Test
{
public:
Test(){}
~Test(){}
public:
//static const int x_;
//1 与static int x_;不同的是,它的初始化可以在类体中进行
//2 但是也只有static const int, static const char(静态常量整型数据成员)才可以在类体中初始化,如double则不行
//但个人还是觉得统一一下,在类体外初始化比较好。
static const int x_ = 100; //静态常量数据成员
};
//const int Test::x_ = 100;
const int Test::x_;
int main(void)
{
Test t;
cout << t.x_ << endl; //output:100
cout << Test::x_ << endl; //output:100
//Test::x_ = Test::x_ + 1; //Error,不能给常量赋值
//t.x_ = t.x_ + 1; //同上
return 0;
}
扩展例子
下面的例子是关于普通成员函数可以访问静态成员函数及静态数据成员,而静态成员函数只能访问静态数据成员,而不能访问普通的数据成员的例子(原因是静态成员函数没有this指针)
#include <iostream>
using namespace std;
class Test
{
public:
Test(int y):y_(y)
{
}
~Test(){}
public:
void TestFun()
{
cout << "x="<< x_ << endl; //非静态成员函数访问静态数据成员
TestStaticFun(); //非静态成员函数访问静态成员函数
}
static void TestStaticFun()
{
//TestFun(); //Error,静态成员函数不能访问非静态成员函数
//cout << "y = "<< y_ << endl; //Error,静态成员函数不能访问非静态成员,因为静态成员函数没有隐含的this指针,故无法指向普通对象的非静态成员。而且也不能访问非静态成员函数,因为非静态成员与非静态成员函数是属于对象的,而静态成员与静态成员函数是属于类的,但是对象可以访问类的静态成员与静态成员函数
cout << "TestStaticFun()..x="<<x_<<endl;
}
static int x_; //静态成员的引用性声明
int y_;
};
int Test::x_ = 100; //静态数据成员的定义性说明。
int main()
{
Test t(10);
t.TestFun();
cout << t.x_ << endl; //对象可以访问静态成员。这是允许的,但是不推荐,让人误解以为x_是属于t对象的。
cout << Test::x_ << endl;//推荐这么访问
return 0;
}