C++类的静态成员详解:成员函数非静态成员函数的非法调用
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。
静态成员的定义或声明要加个关键static。静态成员可通过双冒号来使用<类名>::<静态成员名>。
在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象。希望阅读本文可以使读者对类的静态成员变量和成员函数有更为深刻的认识。
例1:
class Point{
public:
void init(){
//...
}
static void output(){
//...
}
};
int main(){
Point::init(); //作用域调用非静态成员函数
Point::output(); //作用域调用静态成员函数
return 0;
}
编译出错:error C2352: 'Point::init' : illegal call of non-static member function
结论1:不能通过类名来调用类的非静态成员函数。
正确写法为以下代码:
class Point {
public:
void init() {
//...
}
static void output() {
//...
}
};
int main() {
Point p1; //实例化对象
p1.output(); //只能通过对象调用非静态函数
Point::output(); //作用域调用静态成员函数
return 0;
}
编译通过。
结论2:类的对象可以使用静态成员函数和非静态成员函数。
例2:
#include <stdio.h>
class Point{
public:
void init(){}
static void output(){
printf("%d ", m_x); //err
}
private:
int m_x;
};
int main()
Point pt;
pt.output();
return 0;
}
编译出错:error C2597: illegal reference to data member 'Point::m_x' in a static member function
因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。
结论3:静态成员函数中不能引用非静态成员。
例3:
class Point{
public:
void init(){
output();
}
static void output(){}
};
int main(){
Point pt;
pt.output();
return 0;
}
编译通过。
结论4:类的非静态成员函数可以调用用静态成员函数,但反之不能。
例4:
class Point{
public:
Point(){
m_nPointCount++;
}
~Point(){
m_nPointCount--;
}
static void output(){
printf("%d ", m_nPointCount);
}
private:
static int m_nPointCount;
};
int main(){
Point pt;
pt.output();
return 0;
}
编译错误!
这是因为类的静态成员变量在使用前必须先初始化。在main()函数前加Point::m_nPointCount = 0; 再编译链接无错误,运行程序将输出1。
改正:
class Point {
public:
Point() {
m_nPointCount++;
}
~Point() {
m_nPointCount--;
}
static void output() {
printf("%d ", m_nPointCount);
}
private:
static int m_nPointCount;
};
//类静态成员变量初始化赋值
int Point:: m_nPointCount = 0;
int main() {
Point pt;
pt.output();
return 0;
}
编译+运行通过
结论5:类的静态成员变量必须先初始化再使用。
总结:
结论1:不能通过类名来调用类的非静态成员函数。
结论2:类的对象可以使用静态成员函数和非静态成员函数。
结论3:静态成员函数中不能引用非静态成员。
结论4:类的非静态成员函数可以调用用静态成员函数,但反之不能。
结论5:类的静态成员变量必须先初始化再使用。