zoukankan      html  css  js  c++  java
  • c++,static 静态成员变量 / 静态成员函数

    静态成员变量:

    //静态成员变量(static)
    // 
    //1.如果想在同类的多个对象之间实现数据共享 ,可以用静态
    //成员变量,即用static修饰的成员变量,例 static  int a;
    //静态成员变量在项目刚运行的时候就分配内存,项目运
    //行结束以后才销毁。
    // 
    //2.静态成员变量被它所属类创建的所有对象共享。
    // 
    //3.静态成员变量必须在类体外初始化。
    //格式为:类型  类名∷静态成员变量 = 初值
    //例: int Stu :: a = 20; 
    // 
    //4.访问静态成员变量有两种方式:
    // 
    //(1)与普通过成员变量一样,可以通过对象、对象指针或
    //对象引用来访问。
    // 
    //(2)用静态成员变量所属类的类名来访问,
    //即“类名::静态成员变量名”。

    静态成员函数:

    //1、访问静态成员函数的方式有两种
    //    (1)与普通成员函数被访问方式一样,可以用对象、指针和引用来访问
    //    (2)另外,使用 所属类名::静态成员函数名引用。
    
    
    //2、静态成员函数中没有"this.", 而是用"类名::"替代了"this.";
    //(1) static成员函数中不能访问普通的成员。
    //(2)static成员函数可通过 类名::成员 访问静态成员。
    #include <iostream>
    using namespace std ;
    #include <string>
    //---------------------------------------------------------------
    class Demo{//模拟一个人
    public:
        int m_age ;
        char m_name[10] ;
        static int m_country;
    
        Demo(char* s , int age,int country);//构造函数
    
        static void show(void); //介绍自己 
        
        void presence(void); //介绍自己
        
    };
    
    Demo::Demo(char* s ,int age ,int country=111)
    {
        strcpy(this->m_name , s);
        this->m_age = age ;
        this->m_country = country;
    }
    
    //---------------------------------------------------------------
    int Demo::m_country = 111;//china
    
    void Demo::show()
    {
        //cout<<"name:"<<m_name<<endl;//error C2597: 对非静态成员“Demo::m_name”的非法引用
        //cout<<"age:"<<m_age<<endl;//error C2597: 对非静态成员“Demo::m_age”的非法引用
        
        //cout<<"country:"<<this->m_country<<endl;//error C2355: “this”: 只能在非静态成员函数的内部引用
        //cout<<"country:"<<m_country<<endl;//ok 可以访问静态成员
        cout<<"country:"<<Demo::m_country<<endl;//ok 可以访问类名::静态成员
    
    }
    void Demo::presence()
    {
        cout<<"name:"<<m_name<<endl;
        cout<<"age:"<<m_age<<endl;
        cout<<"country:"<<m_country<<endl;//ok
        //cout<<"country:"<<this->m_country<<endl;//ok
        //cout<<"country:"<<Demo::m_country<<endl;//ok
    }
    //----------------------------------------------------------------
    
    int main()
    {
        Demo demo1("caicai"  , 18 , 112);
        demo1.show();
    
        Demo demo2("benben",16);
        demo2.show();
        demo2.presence();
    
    //Demo::m_country是该类对象公有的【地址空间、值】,如本例中demo1、demo2共用。
    //外部函数main可以直接访问静态成员Demo::m_country。
        cout<<"静态成员变量 Demo::m_country="<<Demo::m_country<<endl;
        cout<<"静态成员变量 demo1.m_country="<<demo1.m_country<<endl;
        cout<<"静态成员变量 demo2.m_country="<<demo2.m_country<<endl;
    
        while(1);
    }
    /*
    country:112  //demo1.show();
    country:111  //demo2.show();
    
    name:benben //demo2.presence();
    age:16
    country:111
    */

    C++中的类成员声明static:[1]

    
     在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:
    
    (1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。      
    
    (2)不能将静态成员函数定义为虚函数。      
    
    (3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊 ,变量地址是指向其数据类型的指针 ,函数地址类型是一个“nonmember函数指针”。
    
    (4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就 产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于线程函数身上。[2] [3]
    #include <iostream>// [2]
    using namespace std; #include "windows.h" #include <process.h> class ExampleTask { public: static void taskThread(LPVOID param); friend void funcex(LPVOID param); void func() { cout<<"in func,"<<endl; } }; void funcex(LPVOID param) { cout<<" funcex,"<<endl; ExampleTask *pOeg = (ExampleTask*) param ; pOeg->func(); } void ExampleTask::taskThread(LPVOID param) { ExampleTask *pOeg = (ExampleTask*) param ; pOeg->func(); } int main(int argc, char* argv[]) { ExampleTask realTimeTask; //使用传入指针的方法,用类的静态成员函数调用类的其它函数。 //在c++的语法中,静态成员函数不能操作非静态成员。 realTimeTask.taskThread(&realTimeTask);//测试打印taskThread结果 : in func, //那么,这样定义的意义是什么呢?下面就是一种应用方式:使得类的成员函数可以作为线程函数。 //一般来说,C++的类成员函数不能作为线程函数。这是因为在类中定义的成员函数,编译器会给其加上this指针。 //将类的静态成员函数用作线程函数 _beginthread(ExampleTask::taskThread,0,NULL); //在线程中使用taskThread结果 :in func , //另外,欲要在线程中使用类的方法,也可以使用友元函数。 //将友元函数用作线程函数,这里的话题与static方法无关了。 _beginthread(funcex,0,NULL); // 在友元函数funcex中调用taskThread,再在线程中使用funcex结果 : funcex , in func, while(1); return 0; }
    
    
    
    
    #include <iostream> //[3]
    using namespace std;
    
    #include "windows.h" 
    #include <process.h> 
    
    class CTest
    {
    public:
        CTest();
        ~CTest();
        static DWORD WINAPI ThreadCallback(PVOID pParam);   //这个是系统要的东东,没有对象也能直接访问STATIC成员函数
        DWORD MyProc();
    private:
        HANDLE m_hThread;
    };
    
    CTest::CTest()
        :m_hThread(NULL)
    {
        m_hThread = CreateThread(NULL, 0, ThreadCallback, (LPVOID)this, 0, NULL);  //注意把THIS指针当做PARAM传进去,没这个我们就不用玩了
        //ASSERT(m_hThread);
    }
    
    CTest::~CTest()
    {
        if(m_hThread)
        {
            TerminateThread(m_hThread, 1);
            m_hThread = NULL;
        }
    }
    
    DWORD WINAPI CTest::ThreadCallback(PVOID pParam)//Callback函数可以声明成ThreadCallback(CTest* pCTest),而作为线程的函数参数必须声明成(PVOID pParam)。
    {
        return ((CTest*)pParam)->MyProc();  //把pParam还原成指向当前对象的指针,然后曲线救国一下
    }
    
    DWORD CTest::MyProc()   //这个就是对象里的东西了,在里面可以为所欲为
    {
        //do whatever you want
        //even visit the private member
        cout<<"MyProc"<<endl;
        return 0 ;
    }
    
    int main()
    {
        CTest oTst;
    while(1); return 0 ; }
    
    
    (5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问 时间,节省了子类的内存空间。      
    
    (6)静态数据成员在<定义或说明>时前面加关键字static。      
    
    (7)静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)     
    
    (8)静态成员初始化与一般数据成员初始化不同:
    
    初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
    初始化时不加该成员的访问权限控制符private,public等;        
    初始化时使用作用域运算符来标明它所属类;
               所以我们得出静态数据成员初始化的格式:
    <数据类型><类名>::<静态数据成员名>=<值>
    
    (9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。

    参考:

    1 . C/C++中static关键字作用总结 

      http://www.cnblogs.com/biyeymyhjob/archive/2012/07/19/2598815.html

    2.  类成员函数作为线程函数

      http://blog.163.com/lyz_sea/blog/static/115586707201101025443711/

    3.  静态成员函数运用在CALLBACK函数和线程函数中 

      http://www.cnblogs.com/kanego/articles/2268723.html

  • 相关阅读:
    百度面试题
    分治法--二分查找、乘方、斐波那契数
    01-11李宁老师学Python视频课程(1):初识Python返回课程
    邮件发送的两种实现方法。
    Docker(一):Docker入门教程
    安装docker及在docker中安装python环境学
    vim编辑器的使用和CentOS有很多不同
    大一编程基础培训]==02-03-04-05课==类型
    大一编程基础培训]==08课==条件判断]==07课==Python的LIST与TUPLE数据类型
    Beautiful Soup 4.2.0 文档¶ BeautifulSoup对象内任何第一个标签入口,使用find()方法。
  • 原文地址:https://www.cnblogs.com/mylinux/p/4092415.html
Copyright © 2011-2022 走看看