静态

------------------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】

原文地址:https://www.cnblogs.com/siwuxie095/p/6814964.html