静态

------------------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");

return0;

}

  

//静态成员函数不能加 const

//因为const的本质是给隐形的this指针加const

//而作为静态成员函数根本没有this指针 const加给谁?很显然不可行

//

//普通的静态成员函数可以调用静态成员函数和静态数据成员

//而静态成员函数却无法调用普通成员函数和普通数据成员

//

//静态数据成员和函数并不依赖于对象而是依赖于类

//即如果不实例化一个对象静态数据成员依然在内存中存在

//而普通的数据成员只有在对象实例化后才存在

//

//也因此静态数据成员不在构造函数中实例化其实例化往往单独进行

//

//对象诞生之前,静态数据成员就已经诞生了,且只有一份,随着类的产生而产生

//

//静态数据成员必须单独初始化

  

  

  

  

  

  

  

  

  

  

【made by siwuxie095】