1、静态成员函数、静态数据成员
在类中,用static修饰的成员函数被称为静态成员函数,而用static修饰的数据成员就称为静态数据成员;与普通的成员函数和数据成员不同,
静态成员函数和静态数据成员有自己独有的特点和用法,定义方法如下:
1 class Tank{ 2 public: 3 static void func(void); // 声明静态成员函数 4 .......... 5 private: 6 static int m_iCount; // 声明静态数据成员 7 ....... 8 } 9 10 int Tank::m_iCount = 0; // 初始化静态数据成员 11 12 void Tank::func(void) // 定义静态成员函数 注意不要加 static 13 { 14 ..... 15 }
2、静态成员函数、静态数据成员与普通的成员函数、数据成员有什么区别?
(1)静态成员函数、静态数据成员依赖于具体的类,但是并不依赖于类实例化的对象。
当一个类定义完成之后,我们其实就可以调用这个类的静态成员函数和静态数据成员,而不必实例化一个类对象之后才能使用,
这点与非静态的成员函数和非静态的数据成员是不同的。例如下面所示:
1 #include <iostream> 2 using namespace std; 3 4 class Tank{ 5 public: 6 Tank(void) { m_iCount++; } 7 ~Tank(void) { m_iCount--; } 8 static void func(void); // 申明静态成员函数 9 static int m_iCount; // 声明静态数据成员 10 }; 11 12 ......... // 省略了初始化静态数据成员和静态成员函数定义 13 14 int main(void) 15 { 16 Tank::func(); // 没有实例化类对象而直接使用静态成员函数 17 cout << Tank::m_iCount << endl; // 没有实例化类对象而直接使用静态数据成员 18 return 0; 19 }
(2)静态成员函数不能调用非静态成员函数和非静态成员数据,但是非静态成员函数可以调用静态成员函数和静态成员数据。
这个其实是很好理解的,前面说过,静态成员函数、静态数据成员不依赖于实例化对象,只是随着类定义的出现而存在;
但是非静态数据成员必须是实例化一个具体的对象之后才存在一份属于这个对象的成员数据,而非静态成员函数虽然代码只有一份,
但是因为函数操作的成员数据是依赖于具体的对象的,所以导致成员函数也是依赖于对象的;所以在这种情况下,静态成员函数
是不能操作非静态数据成员和非静态成员函数的,因为先于非静态数据成员诞生,先于非静态成员函数被"激活",就好比是
:你都不知道后面会定义哪些具体的对象,你怎么能够提前就使用呢?但是静态成员函数是可以调用的静态数据成员的。
(3)静态数据成员在内存中只有一份,而非静态数据成员依赖于具体的对象,所以不同的对象都有一份非静态数据成员。
(4)静态数据成员必须单独初始化,不能在类构造函数中进行初始化,实例化类的大小中并不包括静态数据成员。
类的构造函数是实例化一个对象的时候才调用的,而静态数据成员不依赖于对象,所以不能使用构造函数来初始化一个静态数据成员。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 using namespace std; 3 4 class Tank{ 5 public: 6 Tank(char name) { m_cName = name; m_iCount++; } // 构造函数 7 ~Tank(void) { m_iCount--; } // 析构函数 8 int getCount(void) { return m_iCount; } 9 static int func(void); // 申明静态成员函数 10 private: 11 char m_cName; 12 static int m_iCount; // 声明静态数据成员 13 }; 14 15 int Tank::m_iCount = 0; // 静态数据成员的初始化 16 17 int Tank::func(void) 18 { 19 return m_iCount; 20 cout << "Tank---func" << endl; 21 } 22 23 int main(void) 24 { 25 Tank tank('A'); 26 cout << sizeof(tank) << endl; // 测试大小 27 cout << Tank::func() << endl; 28 return 0; 29 }
(5)调用静态成员函数、静态数据成员与调用非静态成员函数、非静态数据成员不同。
静态成员函数、静态数据成员的调用方式有两种:在还没有实例化对象前 和 实例化对象之后,,代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 using namespace std; 3 4 class Tank{ 5 public: 6 Tank(char name) { m_cName = name; m_iCount++; } // 构造函数 7 ~Tank(void) { m_iCount--; } // 析构函数 8 int getCount(void) { return m_iCount; } 9 static int func(void); // 申明静态成员函数 10 private: 11 char m_cName; 12 static int m_iCount; // 声明静态数据成员 13 }; 14 15 int Tank::m_iCount = 0; // 静态数据成员的初始化 16 17 int Tank::func(void) 18 { 19 return m_iCount; 20 cout << "Tank---func" << endl; 21 } 22 23 int main(void) 24 { 25 cout << Tank::func() << endl; // 实例化对象之前 26 27 Tank tank('A'); 28 29 cout << tank.func() << endl; // 实例化对象之后,也可以是 Tank::func() 两种都可以 30 31 return 0; 32 }
(6)在静态成员函数的参数列表中是没有带默认的this指针的,因为this指针是用来指向这个对象的地址的,而我们的静态成员函数不依赖于实例化对象而存在,所以是没有thsi指针的。
所以在函数声明的后面也是不能加上const来进行修饰的,否则编译是会出错的。
在C++中,本人对于 :: 和 . 的理解: class Time;
:: 前面的一般都是一种数据类型,可以是结构体类型和类类型,例如 Time::func(); 表示func这个函数依赖于类(也就是数据类型),并不依赖与对象(也就是具体的变量);
. 前面的一般都是一个具体的对象(也就是变量),例如 Time time; time.set(); 表示set函数依赖于这个对象(也就是变量),既然依赖于这个具体的对象;
以上纯属我自己的理解。