------------------siwuxie095
静态
这里介绍一个关键字:static,即 静态
在 C++ 中提到静态,就不得不提到两个基本概念:
看如下实例:
定义一个坦克类:Tank
在数据成员的前面加一个关键字 static,称之为 静态数据成员,
在成员函数的前面加一个关键字 static,称之为 静态成员函数
静态数据成员和静态成员函数的使用场景:
当进行坦克大战时,希望每一辆坦克作为对象来说,都能够知道
己方还有多少辆坦克的存在,就需要一个静态变量来记录这个值
作为静态数据成员来说,它并不依赖于对象,而是依赖于类,即
如果不实例化对象,s_iCount 在内存中仍然是存在的,这也是静
态数据成员与普通数据成员最大的区别
如果是普通数据成员,则必须要实例化之后,它才能够存在
因为静态数据成员并不依赖于对象的实例化,所以静态数据成员
并不会在构造函数中去初始化,它的初始化往往是单独进行的,
如:int Tank::s_iCount=0;
为静态数据成员初始化时,不要再加 static 关键字,直接写 类型
+类名+数据成员的名称,再赋初值即可
关于 Tank 类的算法:
s_iCount 表示坦克的数量,刚初始化时,坦克的数量是 0,如果
将坦克数量自增的代码写在构造函数中,将坦克数量自减的代码
写在析构函数中,那么每当实例化一个坦克对象,s_iCount 就会
++,每当销毁一辆坦克的对象,s_iCount 就会 --
而作为每个对象来说,都可以通过直接访问 s_iCount 获取到自己
同伴的数量,访问方法有两种,如下:
显然,既可以通过类来访问,也可以通过对象来访问,并且静态数据成员
和静态成员函数的访问方法一致
从内存中进行分析:普通数据成员和静态数据成员的区别
当使用 Tank 类实例化 4 个对象 t1、t2、t3、t4 之后,作为普通
数据成员的 code 就分别随着对象的产生而诞生了,4 个 code 都
有各自的编号,但在这 4 个 code 诞生之前,s_iCount 就已经诞
生了,而且只诞生一次。4 个对象的产生过程中,s_iCount 的值会
变化,但 s_iCount 这个静态数据成员的个数不会发生变化,始终
都是 1 个,即 值变,个数不变
普通成员函数可以调用静态数据成员 或 静态成员函数,反之,
用静态成员函数调用普通数据成员 或 普通成员函数,则不成立
从逻辑上讲,静态数据成员 和 静态成员函数都是随类的产生而产生,
即 它们是依赖于类的,而普通数据成员是依赖于对象的,如果一个对
象都不产生的话,那么在静态成员函数中去调用普通数据成员显然是
会失败的
从 this 指针谈静态成员函数
对 Tank 类略作修改:
在 fire() 和 getCount 中进行调用:
(1)当通过 fire() 调用 s_iCount 时,即 普通成员函数调用静态
数据成员
fire() 看上去一个参数都不传,实际上却传了一个隐形的 this指针,
通过 this 指针就知道当前要调用的是哪一个对象的对应的数据成
员 或 成员函数了,而调用静态数据成员 或 成员函数时,因为它们
并不与对象相关,而只是与类相关,换言之,它们是全局的变量 或
全局的函数,前面有没有 this 也无所谓,用不着区分,直接就去修
改静态数据成员的值 或 调用相应的静态成员函数
(2)当通过 getCount() 调用 m_strCode 时,即 静态成员函数
调用普通数据成员
getCount() 作为静态成员函数来说,它并不会传入一个隐形的
this 指针,这个时候,你又怎么知道你所调用的是数据成员究竟
是哪一个对象的数据成员呢
所以,在静态成员函数中,无法调用非静态的数据成员 或 成员
函数,但是却可以在静态成员函数中去调用静态数据成员 和 静
态成员函数,可以把它们分别看做 全局变量 和 全局函数
即 如果通过静态成员函数去调用一个静态数据成员,没有问题,
而调用一个非静态的数据成员,就会因为 this 指针找不到,无
法确定其是哪个对象的数据成员而造成编译时错误
注意事项
静态数据成员 和 静态成员函数的注意事项:
(1)静态数据成员必须进行单独的初始化,因为它并不随着对象
的产生而产生,而是随着类的产生就已经产生,即 在类产生之后,
对象还没有实例化的情况下,它就应该已经有一个初值,所以,它
不能写到类的构造函数中去初始化,而只能写到类的外边直接进行
初始化
(2)静态成员函数不能调用非静态成员函数和非静态数据成员,
反之则可以调用
(3)静态数据成员只有一份,且不依赖对象而存在,即 如果
通过 sizeof() 去求一个对象的大小,那么它一定是不包含静态
数据成员的
程序:
Tank.h:
#ifndef TANK_H #define TANK_H
class Tank { public: Tank(char code); ~Tank(); void fire(); static int getCount(); private: static int s_iCount; char m_cCode; };
#endif |
Tank.cpp:
#include "Tank.h" #include <iostream> using namespace std;
//首先就进行了初始化(构造函数外实现)前面不需要再加static关键字 int Tank::s_iCount = 0;
Tank::Tank(char code) { m_cCode = code; s_iCount++; cout << "Tank" << endl; }
Tank::~Tank() { s_iCount--; cout << "~Tank" << endl; }
void Tank::fire() { cout << "Tank--fire" << endl; }
//此时不需要再加 static 关键字 int Tank::getCount() { return s_iCount; } |
main.cpp:
#include "stdlib.h" #include "Tank.h" #include <iostream> using namespace std;
int main(void) { Tank *p = new Tank('A');//从堆中实例化对象 cout << Tank::getCount() << endl; Tank *q = new Tank('B'); cout << q->getCount() << endl; delete p; p = NULL; delete q; q = NULL; // 这时对象已经被销毁所以不能再用对象去调用 cout << Tank::getCount() << endl; system("pause"); return 0; }
//静态成员函数不能加 const //因为const的本质是给隐形的this指针加const //而作为静态成员函数根本没有this指针 const加给谁?很显然不可行 // //普通的静态成员函数可以调用静态成员函数和静态数据成员 //而静态成员函数却无法调用普通成员函数和普通数据成员 // //静态数据成员和函数并不依赖于对象而是依赖于类 //即如果不实例化一个对象静态数据成员依然在内存中存在 //而普通的数据成员只有在对象实例化后才存在 // //也因此静态数据成员不在构造函数中实例化其实例化往往单独进行 // //对象诞生之前,静态数据成员就已经诞生了,且只有一份,随着类的产生而产生 // //静态数据成员必须单独初始化 |
【made by siwuxie095】