### 类域

所谓类域是指类的作用域。我们在定义一个类时，类体就是类的作用域，即类域。类的所有成员均处于类域中。当程序中使用点运算符（.）和箭头运算符（->）访问类成员时，编译器会根据运算符前面的对象的类型来确定其类域，并在其类域中查找成员。如果使用域运算符（::）访问类成员，编译器将根据运算符前面的类名来确定其类域，查找类成员。这样，当用户通过对象访问一个不属于类成员的“成员”时，编译器将提示其“成员”没有在类中定义，因为在类域中找不到该成员。

在定义类时，类成员的声明顺序也是很主要的，先声明的成员不能够使用后声明的成员。例如，下面的 CUser 类定义是错误的。

类成员声明顺序

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

int m_nLevel; //操作员级别

public:

void SetLevel(UINT nLevel); //声明一个 SetLevel 方法

typedef unsigned int UINT; //自定义类型 UINT

};

void CUser::SetLevel(UINT nLevel) //定义 SetLevel 方法

{

m_nLevel = nLevel;

}

上述代码中，在声明 SetLevel 方法时参数使用了 UINT 类型，但是该类型在 SetLevel 方法声明前没有被定义，因此出现了语法错误。正确的做法是将 UINT 类型的定义放置在 SetLevel 方法声明的前方。例如：

typedef unsigned int UINT; //自定义类型 UINT

void SetLevel(UINT nLevel);

在类的定义中，通常对象在使用前都需要先声明。这个规则有 2 个例外情况。第一种情况是内联函数。对于内联函数来说，函数的声明被放置在函数定义处处理。因此，类中的所有成员对内联函数都是可见的。

类所有成员对内联函数是可见的

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

void SetLevel(int nLevel) //内联函数

{

m_nLevel = nLevel;

}

int m_nLevel; //定义一个成员变量

};

上述代码即使 m_nLevel 成员的定义出现在 SetLevel 函数定义之后，但是由于 SetLevel 是内联函数，即在函数的定义处访问类的数据成员，自然是合法的。类似于下面的这种情况。

在成员函数的实现部分访问类成员

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

void SetLevel(int nLevel); //声明一个 SetLevel 方法

int m_nLevel; //定义一个 m_nLevel 成员

};

void CUser::SetLevel(int nLevel) //SetLevel 方法的定义

{

m_nLevel = nLevel; //为 m_nLevel 成员赋值

}

在 SetLevel 方法定义中访问了 m_nLevel 成员，这是完全允许的，无可非议。

第 2 种特例的情况出现在成员函数的默认参数。在定义类的成员函数时，可以为成员函数指定默认参数。这个默认参数不仅可以是一个常量值，还可以是类的数据成员，准确地说应该是类的静态数据成员，类的非静态数据成员不能够作为成员函数的默认参数。当我们定义类时，即使类中的静态数据成员出现在成员函数声明之后，它仍然可以作为成员函数的默认参数。例如：

静态成员作为成员函数的默认值

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

void SetLevel(int nLevel = m_nDefalut); //静态成员作为默认参数

int m_nLevel;

static int m_nDefalut; //定义静态数据成员

};

int CUser::m_nDefalut = 1; //初始化静态数据成员

void CUser::SetLevel(int nLevel)

{

m_nLevel = nLevel;

}

上述代码中，静态成员 m_nDefalut 的定义出现在 SetLevel 函数声明的后面，但是它仍然可以作为 SetLevel 函数的默认参数，这是完全合法的。

注意：如果在类中自定义了一个类型，在类域内该类型都被用来解析成员函数参数的类型名。

例如，在类的声明时定义了一个自定义类型。那么允许在方法定义时使用该类型作为参数类型。

类内部的自定义类型作为成员函数参数类型

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

typedef unsigned int UINT; //自定义类型 UINT

void SetLevel(UINT nLevel ); //声明 SetLevel 函数

UINT m_nLevel;

};

void CUser::SetLevel(UINT nLevel) //在类的声明之外使用 UINT 类型

{

m_nLevel = nLevel;

}

上述代码中，在定义 SetLevel 函数时使用了在类 CUser 声明时的自定义类型 UINT。由于类型 UINT 处于 CUser 类域内，因此这是完全合法的，没有必要采用 CUser::UINT 形式。

注意：在对静态数据成员进行初始化时，初始化的语句也被认为时在类域内。

例如，我们在类中定义一个静态数据成员，在全局区域为其初始化时，可以执行使用该类的静态成员函数，而不需要指定类名。

静态数据初始化 1

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

static int m_nLevel; //定义静态数据成员

static int GetLevel() //定义静态成员函数

{

return 1;

}

};

int CUser::m_nLevel = GetLevel(); //利用静态成员函数进行初始化

在上述代码中，语句“int CUser::m_nLevel = GetLevel();”利用 GetLevel 静态成员函数的返回值作为静态成员 m_nLevel 的初始值，由于静态变量初始化的语句处于类域内，因此 GetLevel 函数前不需要指定具体类名，“GetLevel()”与“CUser::GetLevel()”语句的作用是相同的。只是因为静态数据成员初始化时需要指定类域，即“CUser::”，那么当前语句“int CUser::m_nLevel = GetLevel(); ”在“CUser::”之后的部分都处于类域中。但是“int”位于“CUser::”之前，不处于类域内。由于 int 是系统内置的数据类型，因此，编译器能够识别 int。但是，如果静态数据成员的类型是自定义类型，并且自定义类型位于类体的声明中。那么在初始化静态数据成员时，静态数据成员前需要指定具体的类名和自定义类型。例如：

静态数据初始化 2

class CUser //定义一个类

{

private: //设置成员访问级别

char m_Username[128]; //定义数据成员

char m_Password[128]; //定义数据成员

public:

typedef unsigned int UINT; //自定义类型

static UINT m_nLevel; //静态数据成员

static UINT GetLevel() //静态成员函数

{

return 1;

}

};

CUser::UINT CUser::m_nLevel = GetLevel(); //UINT 类型前必须使用类名

上述语句中，如果将“CUser::UINT”改写为“UINT”是不能通过编译的。