• 静态


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

  • 相关阅读:
    POJ 1166 The Clocks 高斯消元 + exgcd(纯属瞎搞)
    防止登录页面出如今frame中
    android--显式跳转和隐式跳转的差别使用方法
    卫星照片
    poj 2586 Y2K Accounting Bug (贪心)
    【转】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型
    【转】在Eclipse中使用PyDev进行Python开发
    【转】eclipse + Pydev 配置Python开发环境
    【转】Python自动化测试 (一) Eclipse+Pydev 搭建开发环境
    【转】Eclipse的启动问题【an error has occurred see the log file】
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/6814964.html
Copyright © 2020-2023  润新知