天天看点

【C/C++】类中的static成员、static const成员和const成员

const 数据成员

const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其 const 数据成员的值可以不同。所以不能在类声明中初始化 const 数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。

 const 数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static const。

static 数据成员

static 数据成员目的是作为类作用域的全局变量,被类里的所有对象共享,即使没有创建任何对象,该成员也存在。static成员变量不能在构造函数初始化列表中初始化,因为它不属于某个对象。在类的内部只是声明,定义必须在类定义体的外部,并且不能在函数体内,通常在类外定义时初始化,或者使用静态函数初始化。借用 gcc 的话:ISO C++ forbids in-class initialization of non-const static member

注意:static 成员变量的内存空间既不是在声明类时分配,也不是在创建对象时分配,而是在编译时在静态数据区分配内存,到程序结束时才释放。

const static 数据成员

const static 数据成员被一个类的所有对象共享,常量,可以在类内定义处初始化,也可以在类外初始化。

const 成员函数

const 成员函数主要是防止修改对象的成员变量(mutable 修饰的成员变量,static 变量除外)。即const成员函数不能修改成员变量的值,但可以访问成员变量。注意 const 成员函数只能保证不修改当前 this 指针所指的对象的成员变量,若通过参数传递进来有别的对象名,是可以修改其成员变量的,还有就是在 const 成员函数里通过 const_cast 移除 *this 的 const 特性后调用一些非 const 成员函数也有可能会改变 *this 对象的成员变量,虽然这种做法其实是错误的。

static 成员函数

static成员函数主要目的是作为类作用域的全局函数,不能访问类的非静态数据成员。类的静态成员函数没有this指针,这导致:

1、静态成员函数可以直接访问类的静态数据和函数成员,而访问非静态成员必须通过参数传递的方式得到一个对象名,然后通过对象名来访问,与其不同的是非静态成员函数可以任意地(非)静态成员函数和(非)静态数据成员;

2、不能被声明为virtual。

注意: 与数据成员不同,static 与 const 不能同时修饰成员函数

原因:const 修饰符用于表示函数不能修改成员变量的值,该函数必须是含有 this指针 的类成员函数,函数调用方式为 __thiscall ,而 static 函数是不含有 this指针 的,调用规约是 __cdecl 或 __stdcall ,两者是冲突的。

下面来一个完整的例子:

#include <iostream>

using namespace std;
class boy
{
	public:
		boy(int _a):a(_a){}                  //常量初始化
		static int Init();                   //静态成员函数声明,只能访问静态数据成员
		void display() const;                //const成员函数声明
		void test();
		static void say();

		const int a;                         //常量定义
		static int b;                        //静态变量声明
		const static int c = 3;              //类内定义+初始化静态常量,与 static const int c = 3 一个意思
};

int boy::b = boy::Init();                            //静态函数初始化静态变量
//int boy::b = 2;                                    //类外定义+初始化静态变量,不用加 static, public, pirvate 等修饰
//const int boy::c = 3;                              //类外定义+初始化静态常量,不用加 static, public, private 等修饰

int boy::Init()
{
	return c;
}

void boy::display() const                             //关键字 const 必须用同样的方式重复出现在函数定义处
{
	cout << a << " " << b << " " << c << endl;
}

void boy::test()                                      //非静态成员函数,可直接访问(非)静态数据成员与(非)静态成员函数
{
	cout << a << " " << b << " " << c << endl;
	display();
	say();
}

void boy::say()                                       //静态成员函数,可直接访问静态数据成员与静态成员函数
{
	cout << b << " " << c << endl;
}

int main()
{
	boy b(1);
	boy d(2);
	cout << b.a << " " << b.b << " " << b.c << endl; //通过对象访问静态数据成员,同理也可通过对象访问静态成员函数
	cout << boy::b << " " << boy::c << endl;         //通过类访问静态数据成员
	b.display();   
	cout << &b.b << " " << &d.b << " " << &boy::b << endl;  //静态数据成员共享同一内存
	b.test();                    
	return 0;
}