zoukankan      html  css  js  c++  java
  • static c/c++/c# 大解析

    static 是由最初的限制和持久过渡到后的共享。
    C语言时代的static 
           在C语言中,只存在函数和变量。
                 A、函数和全局变量,一旦加上static关键字,就限制了其作用域为本文件有效。
                 B、局部变量,一旦加上static关键字,其生命其为整个应用程序。
    C++语言时代的static
          在C++语言中,除了向C语言兼容外,提供了类的支持,同样static在C语言的特性在C++同样有效。
                 C、类的static关键字,在C++的类中,static只能用于修饰数据成员和函数成员(不能修饰构造函数和析构函数),用于该类所具有的信息而不属具体某个对象.
                 D、<注意>如果在类的成员函数中定义了static局部变量,其值会在所有对象中共享!这一点不好!
    C#语言时代的static
           在C#语言中,基于类static访问特性和C++相似。同时,也有了一些改变。
                 E、在C#中,禁止了类成员函数中的局部变量用static修饰。
                 F、类的静态成员字段的初始化更加简单,可以直接在类定义中赋值。初始值设定是按照文本顺序执行,如果类中有静态字段而无静态构造函数,系统会自动生成,并先于静态构造函数执行。
                 G、类提供了static修饰构造函数。类的静态构造函数在给定应用程序域中至多执行一次:只有创建类的实例或者引用类的任何静态成员才激发静态构造函数

    可见static从C-->C++是由简入繁。
    C#作为一种全新的语言,他消除了C++语言的一些复杂性,全面支持面向对象。所以没有C语言的全局函数和全局变量。类成员函数内也不支持静态成员变量了。
    下面用下事例代码,全面阐述以上内容

    /////////////////////////////////////////////////////////////////////////////////////
    //C语言事例A
    //用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.
    //使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
    //c2.c
    int g_i=0;
    static int g_is=0;

    int f1()
    {
        
    return 1;
    }

    static int f2()        
    {
        
    return 2;
    }

    //c1.c
    extern int g_i;        //引用文件c3.h的全局变量
    extern int g_is;    //声明有一个外部全局变量g_is
    extern int f1();
    extern int f2();    
    #include 
    <stdio.h>
    void main()
    {
        printf(
    "%d\n",g_i);
        
    //printf("%d\n",g_is);    //报错
        printf("%d\n",f1());
        
    //printf("%d\n",f2());    //报错,不能访问的函数.
    }

    //C语言事例B
    //局部变通变量与局部静态变量的区别
    //1. 存储空间分配不同
    //auto类型分配在栈上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在静态存储区, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.
    //2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次
    //3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. 
    //c3.c
    #include <stdio.h>
    void Print()
    {
        
    static int a=0;
        
    int b=0;
        a
    ++;        
        b
    ++;
        printf(
    "a = %d,b = %d \n",a,b);
    }

    void main()
    {
        
    for (int i=0; i<3; i++)
            Print();
    }

    //会发现a的会记住上一次的值。具有不可重入性。
    ////////////////////////////////////////////////////////////////////////////////////
    //C++语言事例C
    //很多时候需要将类看作一个整体,当这个整体的一些相关信息就可以用static来维护和管理
    //c4.c
    #include <iostream.h>

    class Test
    {
    private:
        
    int a;
        
    static char creator[16];
    public:
        
    static char* const GetCreator() 
        
    {
            
    //a = 1;            //静态成员函数不能访问类的非静态字段
            return creator;
        }

    }
    ;
    char Test::creator[16]="这是Fung建的类!";

    void main()
    {
          cout
    <<Test::GetCreator()<<endl;
    }

    //C++语言事例D
    //尽量不要在类的成员函数中定义static变量,这可能导致程序混乱.
    //c5.c
    #include <iostream.h>

    class Test
    {
    public:
        
    void fun()
        
    {
            
    static int a=0;
            a 
    += 3;
            cout
    <<a<<endl;
        }

    }
    ;

    void main()
    {
        Test
    * t = new Test();
        t
    ->fun();
        t
    ->fun();
        Test
    * k = new Test();
        k
    ->fun();                //这里第一输出就变成了9
    }

    //★静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。
    //c6.c
    #include <iostream.h>

    class Test
    {
        
    static int s;
        
    int a;
    public:
        
    int fun(int i = s)        //静态数据成员可以成为成员函数的可选参数
        {
            
    return i;
        }

        
    //int fun1(int i = a)    //这个是当然不行了
        
    //{
        
    //    return i;
        
    //}
    }
    ;
    int Test::s = 5;

    void main()
    {
        Test
    * t = new Test();
        cout
    <<t->fun()<<endl;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    //C#语言事例
    //(1)用于对静态字段、只读字段等的初始化。               
    //(2)添加static关键字,不能添加访问修饰符,因为静态构造函数都是私有的。         
    //(3)类的静态构造函数在给定应用程序域中至多执行一次:只有创建类的实例或者引用类的任何静态成员才激发静态构造函数 
    //(4)静态构造函数是不可继承的,而且不能被直接调用。             
    //(5)如果类中包含用来开始执行的 Main 方法,则该类的静态构造函数将在调用 Main 方法之前执行。     
    //    任何带有初始值设定项的静态字段,则在执行该类的静态构造函数时,先要按照文本顺序执行那些初始值设定项。   
    //(6)如果没有编写静态构造函数,而这时类中包含带有初始值设定的静态字段,那么编译器会自动生成默认的静态构造函数。
    using System;
    class Test 

        
    static void Main() {
            Console.WriteLine(
    "{0} {1}", B.Y, A.X);
        }

        
    public static int F(string s) {
            Console.WriteLine(s);
            
    return 1;
        }

    }

    class A
    {
        
    public static int X = Test.F("Init A");
    }

    class B
    {
        
    public static int Y = Test.F("Init B");
    }

    //或者产生如下输出:
    //Init A
    //Init B
    //1 1
    //或者产生如下输出:
    //Init B
    //Init A
    //1 1
    //这是因为 X 的初始值设定项和 Y 的初始值设定项的执行顺序无法预先确定,上述两种顺序都有可能发生;
    //唯一能够确定的是:它们一定会在对那些字段的引用之前发生。但是,下面的示例:
    using System;
    class Test
    {
        
    static void Main() {
            Console.WriteLine(
    "{0} {1}", B.Y, A.X);
        }

        
    public static int F(string s) {
            Console.WriteLine(s);
            
    return 1;
        }

    }

    class A
    {
        
    static A() {}
        
    public static int X = Test.F("Init A");
    }

    class B
    {
        
    static B() {}
        
    public static int Y = Test.F("Init B");
    }

    //所产生的输出必然是:
    //Init B
    //Init A
    //1 1
    //这是因为关于何时执行静态构造函数的规则规定:
    //B 的静态构造函数(以及 B 的静态字段初始值设定项)必须在 A 的静态构造函数和字段初始值设定项之前运行
  • 相关阅读:
    iphone 使用委托(delegate)在不同的窗口之间传递数据
    创建单键模式的类
    读入Plist文件中的信息
    C#读取Excel,取值为空的解决办法!
    ORACLE 常见的数据类型
    ArcGISServer 将内网地图服务映射修改外网可以访问的地图服务
    C#中获取当前路径的几种方法
    sql server2005登录出错问题(转载)
    (转载)服务器控件的生命周期
    ORACLE 中ROWNUM用法总结(转载)
  • 原文地址:https://www.cnblogs.com/freebird92/p/609074.html
Copyright © 2011-2022 走看看