对象的使用

来源:互联网 发布:淘宝店铺地址能改吗 编辑:程序博客网 时间:2024/06/05 09:05

static成员


  • 对特定类型的全体对象而言,有时候需要访问一个全局的变量。比如说统计某种类型对象已创建的数量;
  • 如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这是我们可以用类的静态成员来解决这个问题;
  • 非static数据成员存在于类类型的每个对象中,static数据成员独立该类的任意对象存在,它是与类关联的对象,不与类对象关联。

static成员声明、定义与初始化


  • static成员需要在类定义体外进行初始化与定义
/*---------------------示例代码------------------------*///CountedObject.h #ifndef _COUNTED_OBJECT_H_#define _COUNTED_OBJECT_H_class CountedObject{public:    CountedObject();    ~CountedObject();    static int count_; //静态成员的引用性声明};#endif  //_COUNTED_OBJECT_H_//CountedObject.cpp #include "CountedObject.h"int CountedObject::count_ = 0;  //静态成员的定义性声明,此时不需要指定static                                //静态成员的初始化也必须放在文件作用域CountedObject::CountedObject(){    ++count_;}CountedObject::~CountedObject(){    --count_;}//01.cpp#include "CountedObject.h"#include<iostream>using namespace std;int main(void){    CountedObject ob1;    cout << CountedObject::count_ <<endl;    CountedObject* ob2 = new CountedObject;    cout << CountedObject::count_ <<endl;    delete ob2;    cout << CountedObject::count_ <<endl;    return 0;}

特殊的整型static const成员:整型static const成员可以在类定义体中初始化

#include<iostream>using namespace std;class Test{public:    Test()    {}    ~Test()    {}    static const int x_ = 100;    //静态常量整型成员的初始化可以直接在类体内进行};int main(void){    cout<<Test::x_<<endl;}

static成员优点

  • static成员的名字是在类的作用域中,因此可以避免与其它类成员或全局对象名字冲突
  • 可以实施封装,static成员可以是私有的,而全局对象不可以
  • 阅读程序容易看出static成员与某个类相关联,这种可见性可以清晰地反映程序员的意图

当静态成员声明为私有时,需要提供接口函数

#ifndef _COUNTED_OBJECT_H_#define _COUNTED_OBJECT_H_class CountedObject{public:    CountedObject();    ~CountedObject();public:    static int GetCounnt();//为私有的静态成员提供接口函数private:    static int count_; //静态成员的引用性声明};#endif  //_COUNTED_OBJECT_H_int CountedObject::GetCounnt()  //接口函数{    return count_;}

static成员函数


  • static成员函数没有this指针
  • static成员函数不可以访问非静态成员和非静态成员函数
  • 非静态成员函数可以访问静态成员
class Test{public:    Test(int y) : y_(y)    {    }    ~Test()    {    }    void TestFun()    {        cout<<"x="<<x_<<endl;   //OK,非静态成员函数可以访问静态成员        TestStaticFun();    }    static void TestStaticFun()    {        cout<<"TestStaticFun ..."<<endl;        //TestFun();        Error,静态成员函数不能调用非静态成员函数        //cout<<"y="<<y_<<endl;     Error,静态成员函数不能访问非静态成员    }    static int x_;      // 静态成员的引用性说明    int y_;};

类/对象大小计算

  • 类大小计算遵循前面学过的结构体对齐原则
  • 类的大小与数据成员有关与成员函数无关
  • 类的大小与静态数据成员无关
  • 虚函数对类的大小的影响
  • 虚继承对类的大小的影响

四种对象的作用域与生存期

栈对象

隐含调用构造函数(程序中没有显示调用)

堆对象

隐含调用构造函数(程序中没有显示调用)

全局对象、静态全局对象

  • 全局对象的构造先于main函数
  • 已初始化的全局变量或静态全局对象存储于.data段中
  • 未初始化的全局变量或静态全局对象存储于.bss段中

静态局部对象

  • 已初始化的静态局部变量存储于.data段中
  • 未初始化的静态局部变量存储于.bss段中

内存分区

static用法总结

C语言中的用法

  • 用于函数内部修饰变量,即函数内的静态变量。这种变量的生存期长于该函数,使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3);
  • 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。专业的说法叫“具有internal linkage”(简言之:不暴露给别的translation unit)。

C++中添加的用法

  • 用于修饰类的数据成员,即所谓“静态成员”。这种数据成员的生存期大于class的对象(实例/instance)。静态数据成员是每个class有一份,普通数据成员是每个instance 有一份;
  • 用于修饰class的成员函数,即所谓“静态成员函数”。这种成员函数只能访问静态成员和其他静态程员函数,不能访问非静态成员和非静态成员函数。

static与单例模式

  • 保证一个类只有一个实例,并提供一个全局访问点
  • 禁止拷贝
#include<iostream>using namespace std;class Singleton{public:    static Singleton* GetInstance()  //2. 提供一个全局访问点    {        if(instance_ == NULL)        {            instance_ = new Singleton; //构造        }        return instance_;    }    ~Singleton()    {        cout << "~Singleton ..."<<endl;    }private:    Singleton()                     //1. 将构造函数声明为私有的    {        cout<< "Singleton ..."<<endl;    }    Singleton(const Singleton& other);            //    Singleton& operator=(const Singleton& other); //3. 将拷贝构造函数与等号运算符都声明为私有的,斌企鹅不提供其实现方式,那么就可以禁止拷贝了    static Singleton* instance_;};Singleton* Singleton::instance_;int main(void){    Singleton* s1 = Singleton::GetInstance();//    Singleton* s2 = Singleton::GetInstance();//  二者调用的是同一个实例    return 0;}

需要注意的是以上程序运行时系统是不会调用析构函数的,所以需要进一步改造
程序结果

  • 方案一:
#include<iostream>using namespace std;class Singleton{public:    static Singleton* GetInstance()    {        if(instance_ == NULL)        {            instance_ = new Singleton; //        }        return instance_;    }    ~Singleton()    {        cout << "~Singleton ..."<<endl;    }    class Garbo   //1. 提供一个嵌套类,在该类中进行释放    {    public:        ~Garbo()        {            if(Singleton::instance_ != NULL)            {                delete Singleton::instance_;            }        }    };private:    Singleton()    {        cout<< "Singleton ..."<<endl;    }    Singleton(const Singleton& other);    Singleton& operator=(const Singleton& other);    static Singleton* instance_;    static Garbo garbo_;    //2. 当该对象生存周期结束时自动调用析构函数,从而达到};Singleton::Garbo Singleton::garbo_; // 3. 此处必须声明Singleton* Singleton::instance_;int main(void){    Singleton* s1 = Singleton::GetInstance();    Singleton* s2 = Singleton::GetInstance();    return 0;}
  • 方案二(推荐):
#include<iostream>using namespace std;class Singleton{public:    static Singleton& GetInstance()  //全局访问点    {        static Singleton instance;   //局部静态成员        return instance;    }    ~Singleton()    {        cout << "~Singleton ..."<<endl;    }private:    Singleton()    {        cout<< "Singleton ..."<<endl;    }    Singleton(const Singleton& other);    Singleton& operator=(const Singleton& other);};int main(void){    Singleton& s1 = Singleton::GetInstance();    Singleton& s2 = Singleton::GetInstance();    return 0;}

const成员函数

  • const成员函数不会修改对象的状态
  • const成员函数只能访问数据成员的值,而不能修改它
class Test{public:    Test(int x):x_(x)    {}    int GetX() const    {        return x_;    }private:    int x_;};

const对象

  • 如果把一个对象指定为const,就是告诉编译器不要修改它;
  • const对象的定义:
    const 类名 对象名(参数表)
  • const对象不能调用非const成员函数
int main(void){    const Test t(10);  //const对象,对象的状态不能被更改,不能调用非const成员函数    cout << t.GetX() << endl; //GetX()为const成员函数,因此t可以调用    return 0;}

mutable

  • 用mutable修饰的数据成员即使在const对象或在const成员函数中都可以被修改
class Test{public:    Test(int x):x_(x),outputtimes_(0)    {}    int GetX() const    {        return x_;    }    void OutPutX() const    {        cout << "x = "<<x_<<endl;        outputtimes_++;       //outputtimes_已被声明为mutable,此处可以修改它的值    }    int GetOutPutTimes() const    {        return outputtimes_;    }private:    int x_;    mutable int outputtimes_;};
0 0