zoukankan      html  css  js  c++  java
  • C++之static的应用

    static关键字是C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种在C/C++语言中使用, 第三种只在C++中使用

    (1)局部静态变量

    (2)外部静态变量/函数

    (3)静态数据成员/成员函数

    一、局部静态变量

    在C/C++中, 局部变量按照存储形式可分为三种auto, static, register

    与auto类型(普通)局部变量相比, static局部变量有三点不同

    1. 存储空间分配不同

    auto类型分配在上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在态存储, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.

    2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次

    3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象实例如果不初始化, 则会自动调用默认构造函数, 不管是否是static类型)

    特点: static局部变量的”记忆性”与生存期的”全局性”

    所谓”记忆性”是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值.

    示例程序一

    #include <iostream>

    using namespace std;

    void staticLocalVar()

    {

    static int a = 0; // 运行期时初始化一次, 下次再调用时, 不进行初始化工作

    cout<<"a="<<a<<endl;

    ++a;

    }

    int main()

    {

    staticLocalVar(); // 第一次调用, 输出a=0

    staticLocalVar(); // 第二次调用, 记忆了第一次退出时的值, 输出a=1

    return 0;

    }

    注意事项:

    1. “记忆性”, 程序运行很重要的一点就是可重复性, 而static变量的”记忆性”破坏了这种可重复性, 造成不同时刻至运行的结果可能不同.

    2. “生存期”全局性和唯一性. 普通的local变量的存储空间分配在stack上, 因此每次调用函数时, 分配的空间都可能不一样, 而static具有全局唯一性的特点, 每次调用时, 都指向同一块内存, 这就造成一个很重要的问题 ---- 不可重入性!!!

    二、外部静态变量/函数

    在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.

    使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

    示例程序三:

    //file1.cpp

    static int varA;

    int varB;

    extern void funA()

    {

      ……

    }

    static void funB()

    {

      ……

    }

    //file2.cpp

    extern int varB; // 使用file1.cpp中定义的全局变量

    extern int varA; // 错误! varA是static类型, 无法在其他文件中使用

    extern vod funA(); // 使用file1.cpp中定义的函数

    extern void funB(); // 错误! 无法使用file1.cpp文件中static函数

    关于extern的知识

      extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义

    三、静态数据成员/成员函数(C++特有)

    静态成员变量:

            对于所有的对象共有一个成员变量的就用static ,提供一个所有对象共有的一个成员变量比“每一个类对象维护一个成员变量” 要更有效。

    在这种情况下类的静态数据成员提供了一个更好的方案静态数据成员被当作该类类型的全局对象,对于非静态数据成员,每个类对象都有自己的拷贝而静态数据成员对每个类类型只有一个拷贝静态数据成员,只有一份由该类类型的所有对象共享访问。同全局对象相比使用静态数据成员有两个优势 1 静态数据成员没有进入程序的全局名字空间因此不存在与程序中其他全局名字冲突的可能性 2 可以实现信息隐藏静态成员可以是private 成员而全局对象不能 在类体中的数据成员声明前面加上关键字static 就使该数据成员成为静态的static 数据成员,遵从public/private/protected 访问规则,例如在下面定义的Account 类中_interestRate是被声明为double 型的私有静态成员

    class Account { Account( double amount, const string &owner ); string owner() { return _owner; }

     

    static double getRate(){return _interestRate;} private: static double _interestRate; double _amount; string  _owner; };

    为什么把_interestRate 声明为static 而_amount 和_owner 不呢,这是因为每个Account对应不同的主人有不同数目的钱而所有Account 的利率却是相同的,因为在整个程序中只有一个_interestRate 数据成员它被所有Account对象共享,所以把_interestRate声明为静态成员,减少每个Account对象所需的存储空间。

          静态成员函数:静态成员函数一般只能访问静态成员变量,如果要访问非静态成员变量的话,只能访问某一个对象的非静态成员变量和静态成员函数。可以传一个对象的指针,引用等参数给这个静态成员函数。

    class a

    { public:   a():m_ia(123) {}   int getia() { return m_ia; }     static int f(a &aa) { return aa.getia(); } private: int m_ia; };

    void main() { a aa; cout<<a::f(aa); }

    静态成员函数中是不能调用非静态成员的,包括非静态成员函数和非静态成员变量。那么在非静态成员函数中是否可以调用静态成员函数呢?答案是肯定的,因为静态成员函数属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员函数的。其实,我们也可以以一个内存模型这个角度来考虑,也就是说,无论采取什么样的操作,程序代码都是在内存中运行的,只有在内存中占有了一席之地,我们才能访问它。如果一个成员函数或成员变量还没有在内存中产生,结果是无法访问它的。所有静态成员函数只能访问静态成员变量。(讲的真好!!!)

    使用static关键字声明的函数成员使静态的,静态成员函数同样也属于整个类,由同一个类的所有对象共同维护,为这些对象所共享.     作为成员函数,它的访问属性可以受到类的严格控制,对于公有的静态函数成员函数,可以通过类名或对象名来调用,但一般情况下建议用对象名来引用静态函数成员.注意,一般的成员函数只能通过对象名来调用.       由于一个类的静态成员函数只有一个拷贝,因此它访问对象的数据和函数时受到了限制.静态成员函数可以直接访问该类的静态数据成员.而访问非静态数据成员, 必须通过参数传递方式得到对象名,然后通过对象名来访问.可以看到,通过静态函数成员访问非静态成员使相当麻烦的,一般的使用中,它主要用来访问全局变量或同一个类中的静态数据成员,特别是和后者一起使用,达到对同一个类中对象之间共享的数据进行维护的目的.       构造函数和析构函数不可以定义为static,构造函数要给每一个对象一个this指针如果可以是静态的,它如何构造和访问this指针? 明显是不可以的!

    静态成员变量一般要在.cpp文件里进行定义:double Account::_interestRate = 0.0589;静态成员函数的声明除了在类体中的函数声明前加上关键字static 以及不能声明为const 或volatile 之外与非静态成员函数相同,出现在类体外的函数定义不能指定关键字static.

      const string str = "liangxueliang"; Account *Acc = new Account(222222,str); Acc->getRate(); Account::getRate();

  • 相关阅读:
    学习Timer定时器
    C++ 延时等待(sleep/timer/wait)
    MFC学习问题总结
    node.js
    总结
    关于Windows
    关于数组
    每周一次
    每周一次
    每周一次
  • 原文地址:https://www.cnblogs.com/hainanlinyu/p/3293581.html
Copyright © 2011-2022 走看看