C++静态成员和静态成员函数

为什么引入static声明

引入static的声明的目的,是给linker提供一个提示,表明相应的变量或函数是“内部”的。

例如,在一个cpp文件中,static声明的全局变量属于这个文件,不能被其他文件进行extern

同样的道理,在类内部声明的static变量和函数,表示这个变量或函数是类内部的,属于这个类,不能被类外部所使用。

在类中使用static,是为了避免使用全局变量,污染整个命名空间(作用域限制在类内),同时,还可以使用全局特性(static不在栈上创建)。

static成员函数和成员变量

从这个角度来理解static就能明白其表现出来的特性了。

1.对于static成员函数来说:

1)static声明的成员函数只能访问在同一个类内的static变量,而不能访问非static的(因为non-static的成员都是属于对象的,需要构造函数进行初始化的);

2)static成员函数不能使用this指针,因为this指针指向的是具体的对象;

3)static成员函数可以在类定义中定义,或者在类定义中声明后,在别处定义

(类中定义的成员函数视为inline,是固定的,在构造对象时,即使每个对象都有一个static函数的副本,这些副本并没有什么不同,对外的表现仍是唯一定义,所以static成员函数在类定义时定义没有问题)。

2.对于static成员变量来说(非const):

1)只能在类定义中声明,不能进行初始化;

2)不能通过构造函数进行初始化,因为不属于任何对象;

3)必须在类定义的外部进行初始化

static变量如果内联到类定义中,每个对象中都有一个副本。然而,这个变量是可以被修改的,会造成同一类型的不同对象中存在不同的static变量值,违反了static变量具有全局特性的初衷)。

至于对static成员变量和成员函数的访问,则可以通过类(用::操作符)或者对象(变量,指针,引用等)进行访问,对其的访问控制仍然受到访问控制符(publicprivateprotected)的限制。

class Base{
public:
    static int default_int;     //Static变量仅仅能够在类定义中声明,不能初始化
    static void change_int(int);//Static函数可以声明
    static void change_char(char x){default_char=x;} //Static函数也可以定义
private:
    static char default_char;
}

//在类外部定义static变量和static成员函数
int Base::default_int{1};

char Base::default_char{'a'};

void Base::change_int(int x){default_int=x;}

//访问static成员

using namespace std;

int main()
{
    Base A{};
    Base B{};
    cout << "Access by object:" << A.default_int << endl
         << "Access by class:" << Base::default_int << endl;
    cout << "Cannot access private:" << A.default_char << endl; //Error!访问控制符限制
    A.change_int(10);//使用对象A来访问static方法,改变static变量的值
    cout << "Changed static member:" << B.default_int << endl; 
    //static成员属于类的,通过另一个同类型对象访问这个static变量,其值改变
    A.change_char('x');
}

使用const声明

再说一些关于const声明的问题:

1.const static成员,使用了const关键字表示这个成员变量是个常数,不会改变,因此必须在类定义中对其进行初始化,而不能在类定义外部。

这个限制其实跟static没关系,本质上是const声明的要求(类中定义的const变量和引用必须进行初始化,而且是在类定义的时候进行,不能在对象构造期间进行,因此这两种类型的变量要么定义时初始化,要么通过in-class的构造函数初始化)。

但是对于const static,要求更为严格,并不是所有类型都可以这样使用,只有intenumconstexpr才可以在类定义的内部进行初始化(属于类的,而且还要求是常量,通常只用于表示symbolic作用的变量)。

2.static成员函数不能声明为const,因为const声明表明函数不会改变类的成员变量,而static成员函数根本不能访问类中的非static成员,不符合const的要求。

最后,关于static成员变量的另一个用法,可以在类内声明自身类型的static变量,而不能声明自身类型的非static变量。这是因为非static的变量需要构造函数进行初始化,而对自身类型的变量进行初始化又会调用构造函数,从而陷入无限循环。这样,在类定义中声明自身类型的变量,只能通过指针或者引用(指针在初始化时可以赋值nullptr,引用一定会被初始化成另一个对象的引用,不会出错)。相反,使用static声明表明这个变量是在其他地方定义的,不用关心其对应的对象是如何构造的。例如:

class Base{
public:
    static Base A;  //声明自身类型的成员变量,没问题
    Base B;         //Error!不能声明自身类型的非static成员变量
    Base *C;        //OK,C会被默认构造函数初始化成nullptr
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值