9.2 类定义的作用域与可见域

    同函数一样,类的定义没有生存期的概念,但类的定义有作用域和可见域。

    使用类名创建类的对象时,首要的前提是类名可见,类名是否可见取决于类定义的可见域,该可见域同样包含在其作用域中,类本身可被定义在3种作用域内,这也是类定义的作用域。

    1.全局作用域

    在函数和其他类定义的外部所定义的类称为全局类,绝大多数的C++类是定义在该作用域中,我们在前面定义的所有类都是在全局作用域中,全局类具有全局作用域。

    2.类作用域

    一个类可以定义在另一类的定义中,这是所谓的嵌套类。举例来说,如果类A定义在类B中,A的访问权限是public,则A的作用域可认为和B的作用域相同,不同之处在于必须使用B:A的形式访问A的类名。当然,如果A的访问权限是private,则只能在类内使用类名来创建该类的对象,无法在外部创建A类的对象。代码9.2展示了嵌套类的应用。

    代码9.2 public嵌套类PublicClassSample


    <—————————————文件名:line.h——————————————————> 01 #include<iostream> 02 using namespace std; 03 class line//line类定义 04 { 05 public: 06 class point//point类定义在line类内,public属性,外部可访问 07 { 08 private://point类内私有成员列表 09 int x; 10 int y; 11 public: 12 point(int xp=0,int yp=0)//point类构造函数,带默认参数值 13 { 14 x=xp; 15 y=yp; 16 } 17 void printpoint();//point类成员函数原型,外部实现 18 }; 19 private: 20 point p1,p2;//line内两个point对象成员 21 public: 22 line(int x1,int y1,int x2,int y2):p1(x1,y1),p2(x2,y2)//构造函数,初始化表 23 { 24 } 25 void printline()//输出提示信息 26 { 27 p1. printpoint();//调用对象成员的公共成员 28 cout<<"———->"; 29 p2. printpoint();//调用对象成员的公共成员 30 cout<<endl; 31 } 32 }; <————————————文件名:example902.cpp———————————————> 33 #include"line.h"//包含line类和point类定义的头文件 34 void line:point:printpoint()//point类中函数printpoint()的实现,注意双重作用域限定符 35 { 36 cout<<"("<<x<<","<<y<<")"; 37 } 38 int main() 39 { 40 line line1(1,2,3,4);//调用line类构造函数,声明一个line类的对象line1 41 line1. printline();//输出提示信息 42 line:point pt(1,3);//以line:point访问point类定义,声明一个point类的对象pt 43 pt. printpoint();//输出提示信息 44 cout<<endl;//为整齐美观,换行 45 return 0; 46 }

    输出结果如下所示。


    (1,2)———->(3,4) (1,3)

    【代码解析】代码第6行的point类定义在line类里,嵌套类point的成员函数既可以定义成内联的,也可以在类line外定义,但要合理使用作用域限定符“:”。

    注意

    嵌套类的成员函数不能内联在外部类中。

    point类定义的访问权限是public,因此,不仅可以在line类内通过诸如“point pt1;”的形式创建point类对象,还可以在line类外部使用诸如“line:point pt(1,3);”的形式创建point类对象,此时,point类既可在line内可见,也可在line外可见,其作用域与全局类line相同。

    如果point类定义的访问权限是private,则只能在line类内创建point类对象,在line类外部无法再通过“line:point”的形式访问point类名,此时,point类名只在嵌套类line内可见。

    3.块作用域

    类的定义在代码块中,这是所谓的局部类,该类完全被块包含,其作用域仅仅限于定义所在块,不能在块外使用类名声明该类的对象,如代码9.3所示。

    代码9.3 块作用域类ClassInBlock


    <————————————文件名:example903.cpp———————————————> 01 #include<iostream> 02 using namespace std; 03 int main() 04 { 05 void Work(int,int); //Work函数原型声明 06 Work(5,6); //Work函数调用 07 return 0; 08 } 09 void Work(int a,int b) 10 { 11 class point //类定义在函数内,在函数外无法使用point创建对象 12 { 13 private: 14 int x,y; 15 public: 16 point(int xp=0,int yp=0) 17 { 18 x=xp; 19 y=yp; 20 } 21 void print() 22 { 23 cout<<x<<","<<y<<endl; 24 } 25 }; 26 point pt(a,b); //函数内,创建point类的对象pt 27 pt.print(); //输出提示信息 28 }

    输出结果如下所示。


    5,6

    【代码解析】代码第11行的point类是在函数Work中定义的局部类,因此,只能在Work函数访问类名,通过类名声明该类对象,在Work函数外(如main函数中)不能访问point类,如果在main函数中使用了诸如“point pt1;”的语句,编译器将会指出“point类未定义”。

    注意

    局部类必须完全定义在局部作用域内。所以,它的所有成员函数必须是内联的,这就决定了局部类的成员函数都是很简单的。

    4.类名也存在覆盖

    和普通变量的覆盖原则一样,类名也存在“屏蔽”和“覆盖”,不过,依旧可使用作用域声明符“:”指定具体使用的类名,如“:类名”访问的是全局类,使用“外部类:嵌套类”访问嵌套类。

    注意

    在类成员函数内可用“this->成员名”的形式访问类成员,但不能用“this->嵌套类名”的形式访问嵌套类。