基本语法
- 静态成员提供了一个同类对象的共享机制,静态成员变量属于整个类,该类所定义的对象共享同一个静态成员变量(无论定义多少个对象,他们的static成员变量都是同一个)。
- 静态成员变量必须在外部声明并初始化。
- 静态成员函数中不能使用非静态成员变量,因为静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针。静态成员是属于整个类的,他不依赖于某个对象,而普通成员函数专属于类定义的个某个对象,这时候如果调用该静态成员函数,编译器不知道该函数中被引用的普通成员变量属于哪个具体对象,故报错(具体将在下面代码中详细分析)。
代码分析
代码如下:
#include <iostream> using namespace std; class MyClassA { public: MyClassA() { a = 10; cout << "无参构造函数调用" << endl; } void PrintA() { cout << "静态成员 a = " << a << endl; } public: static int a; }; int MyClassA::a = 0; //必须在外部定义!!!否则报错 //错误 LNK2001 无法解析的外部符号 "public: static int MyClassA::a" //静态成员变量测试 void FuncTest1() { MyClassA A1, A2; A1.PrintA(); //静态成员变量的第一种访问方式 A2.a++; A1.PrintA(); //静态成员变量的第二种访问方式 MyClassA::a++; A1.PrintA(); A2.PrintA(); } class MyClassB { public: static void PrintStaticValue() { cout << "静态成员函数中的静态变量 " << "b2 = " << b2 << endl; } static void PrintValue() { //cout << "静态成员函数中的非静态变量 " << "b1 = " << b1 << endl; //错误(活动) E0245 非静态成员引用必须与特定对象相对 //错误 C2597 对非静态成员“MyClassB::b1”的非法引用 } /* 静态成员函数中只能使用静态变量,不能使用非静态成员变量,因为非静态成员变量是属于某个对象的, 当我们 MyClassB::PrintValue() 的时候,编译器不知道该使用哪个对象(B1还是B2还是B3...)的非 成员变量b1 */ private: int b1; static int b2; }; int MyClassB::b2 = 0; //静态成员函数测试 void FuncTest2() { MyClassB B; //静态成员函数的第一种调用方式 B.PrintStaticValue(); //静态成员函数的第二种调用方式 MyClassB::PrintStaticValue(); MyClassB B1, B2, B3; //MyClassB::PrintValue(); //我应该使用哪个b1???是打印B1的b1,还是打印B2的b1,又或者是B3的b1? //故报错 } int main() { FuncTest1(); FuncTest2(); system("pause"); return 0; }
成员变量与成员函数的存储与this指针
C++类对象中的成员变量和成员函数是分开存储的
- 成员变量:
①普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节 对齐方式。
②静态成员变量:存储于全局数据区中。 - 成员函数:存储于代码段中。
既然类的成员函数存储在代码区,也就是说所有的对象共用一块代码,那么当具体对象调用成员函数的时候,怎么区分成员函数中使用的变量是哪个对象的呢?比如:
class MyClass { public: void PrintValue() { a = 10; cout << a << endl; } public: int a; }; int main() { MyClass A1, A2, A3; A1.PrintValue(); system("pause"); return 0; }
在上段代码中,PrintValue函数中用的变量a是A1的还是A2的还是A3的呢?
C++编译器会对成员函数进行内部处理,加一个this指针,this指针指向调用该成员函数的对象,这样就知道是哪个对象调用了该成员函数,并使用该对象的成员变量值。代码如下:
void PrintValue(MyClass* this) { this->a = 10; cout << this->a << endl; }
在调用的时候
A1.PrintValue();
会被转化为
PrintValue(&A1);
由此可见,这也是使用了C语言的指针实现的。实际上,面向对象也是在面向过程的基础上实现的,只不过是在此基础上加了一层封装,对用户进行了隐藏而已。
对于静态成员函数,不会做这种转化,因为静态成员函数是属于整个类的,这也正是为什么静态成员函数中不能使用非静态成员变量,因为静态成员函数中没有this指针,编译器不知道使用的成员变量是哪个对象的变量。
普通成员函数都包含指向具体对象的this指针,哪个对象调用成员函数,this指针就指向这个对象。
系列文章
【四、const与this指针详解】详解C与C++中const的异同,类中的const