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;
}