C++程序设计案例实训教程第10章

来源:互联网 发布:linux怎么退出top命令 编辑:程序博客网 时间:2024/06/08 06:36

10章  关于对象的高级专题

数据的共享和保护机制是C++的重要特性之一。其包含的内容主要为标识符的作用域、可见性和生存期,通过类的静态成员实现同一个类的不同对象之间数据和操作的共享,通过常成员来设置成员的保护属性。作用域是一个标识符在程序正文中有效的区域。类可以被看成是一组有名成员的集合,类X的成员N具有类作用域。可见性指程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。对象从诞生到结束的时间为它的生存期。在生存期内,对象将保持它状态(即数据成员的值),变量也将保持它的值不变,直到它们被更新为止。友元关系提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。

如果没有重载机制,那么对不同类型的数据进行相同的操作也需要定义名称完全不同的函数;重载是指两个以上的函数,具有相同的函数名,但是形参的个数或类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数。运算符重载的实质也是函数重载,运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时导致不同的行为。运算符也可以重载为类的友元函数,这样它就可以自由地访问该类的任何成员。

10.1  类的作用域

案例10-1  类的作用域

【实例描述】

前面学习了局部作用域和全局作用域,类也有作用域,所有的类成员是属于类作用域的。类本身可被定义在三种作用域内:全局作用域、 在另一个类的作用域中和 在一个块的局部作用域中。本实例效果如图10-1所示。

 

10-1  类的作用域

【实现过程】

声明一个类Rectangle,程序分两个演示:取最大值函数max()和连乘3次函数cude(),它们分别定义同名的外部变量与局部变量,输出结果。代码实现如下:

#include <iostream>

#include <typeinfo>

using namespace std;

class Rectangle {

        public:

        Rectangle (int, int, int, int);

        private:

        class Point {

        public:

        Point (int, int);

        private:

        int x, y;

        };

        Point topLeft, botRight;

        };

void Render (void)

      {

      class ColorTable {

      public:

      ColorTable(void) { /* ... */ }

      AddEntry(int r, int g, int b) { /* ... */ }

      };

      ColorTable colors;

      }

int main()

{

   ColorTable ct; // 非法,没有定义ColorTable!

   return 1;

};

【案例分析】

1Point嵌套在Rectangle类中,Point成员函数可定义为内联的,也可在全局作用域中,但后者对成员函数名需要更多的限制。同样,在类域外访问嵌套类需要限制类名。

2ColorTable是在函数Render中的局部类。与嵌套类不同的是:局部类不能在其局部作用域外访问,例如:ColorTable ct;会出现“非法,没有定义ColorTable类”错误提示。

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

案例10-2  类定义的作用域

【实例描述】

每个类都定义了自己的新作用域和唯一的类型。在类的定义体内声明内成员,将成员名引入类的作用域。两个不同的类具有两个不同的类作用域。本实例效果如图10-2所示。

 

10-2  超出作用域错误实例

【实现过程】

声明二个类FirstSecond用完全限定名Sales_item::avg_price来指定这是类Sales_item作用域中的avg_price成员的定义。代码实现如下:

#include <iostream>

#include <typeinfo>

class First {

int memi;

double memd;

 };

class Second {

int memi;

double memd;

};

int main()

{

class First;

class *ptr = &First;

ptr-memi=0;

ptr->memd=1.23;

}

【案例分析】

1一旦看到完全限定名,就知道该定义是在类作用域中。因为是在类作用域中 所一调用 revenue和units_sold不需要写成 this->revenue或this->units_sold。同时,定义于类外部的成员函数中,形参表和成员函数体都出现在成员名之后,这些都是在类作用域中定义,所以可以不用限定而引用其他成员。

2与形参类型相比,返回类型定义在成员名字前面。如果函数在类定义体外定义,那么用于返回类型的名字在类作用域之外。如果返回类型使用由类定义的类型,则必须使用完全限定名

10.3  对象生存期、作用域和可见域

案例10-3  超出作用域错误实例

【实例描述】

作用域是指程序中所说明的标识符在哪一个区间内有效,即在哪一个区间内可以使用或引用该标识符。本实例讨论在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内外部变量不起作用。本实例效果如图10-3所示。

 

10-3  超出作用域错误实例

【实现过程】

程序分两个演示:取最大值函数max()和连乘3次函数cude(),它们分别定义同名的外部变量与局部变量,输出结果。代码实现如下:

#include <iostream.h>

#include <iostream>

int  a=3, b=5;

int max(int  a, int  b) //取最大值

{   int c;

    c=a>b? a:b; //取最大值

    return  c; //返回最大值

}

void demo1(void)

{  

int   a=8;

    cout<<max(a,b)<<endl; //调用取最大值函数

}

int  x;

void cude(void)

{  x=x*x*x ; //连乘3

}

void demo2 (void)

{    x=5;

     cude ( );

     cout<<x<<endl;

}

int main()

{

     demo1();

 demo2();

 system("pause");

 return 0;

}

【案例分析】

1)在同一个源文件中,如外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用。

2)在C++中,作用域共分为五类:块作用域、文件作用域、函数原型作用域、函数作用域和类的作用域。

案例10-4  作用域的相互屏蔽例程

【实例描述】

本实例继续讨论作用域。在块作用域内可通过作用域运算符“::”来引用与局部变量同名的全局变量。本例效果如图10-4所示。

 

10-4  作用域的相互屏蔽例程

【实现过程】

程序定义外部变量i,主函数main()定义局部变量i、j,用::符号访问外部变量,输出变量的值。代码实现如下:

#include <iostream.h>

#include <iostream>

int  i= 200;

int main()

{

   int i , j=60;

   i=28; //访问局部变量i

   ::i= ::i+10; //访问全部变量i

   j= ::i+i; //访问全部变量i和局部变量j

  cout<<"::i="<<::i<<endl ;

  cout<<"i="<<i<<endl ;

  cout<<"j="<<j<<endl ;

  system("pause");

  return 0;

}

【案例分析】

1)块作用域:用花括号括起来的一部分程序称为一个块。在块内说明的标识符,只能在该块内引用,即其作用域在该块内,其范围开始于标识符的定义处,结束于块的结尾处。

2)全局变量的作用域称为文件作用域,即在整个文件中都是可以访问的。在函数原型的参数表中说明的标识符所具有的作用域称为函数原型作用域,从其定义处开始,到函数原型说明的结束处结束。

 

提示:可以在函数原型说明中只作参数的类型说明,而省略参量名如float calc(int ,  float)

10.4  类的友元

案例10-5  乡村生产总值

【实例描述】

在面向对象设计的类中,运算符重载的方式有成员函数和友元函数两种形式,前者运算符的声明与成员函数类似,左操作无须用参数输入,而是通过隐含的this指针传入;后者采用友元重载形式,这没有隐含的参数this指针。本例定义农作物类,重载友元重载运算符号(+)和(>),实现生产总值和产值比较,实现效果如图10-5所示。

 

10-5  乡村生产总值

【实现过程】

定义农作物类crops,该类的私有成员output、area、total为单产、种植面积和生产总值;定义类成员函数gettotal()dispTotal()为返回生产总值和显示生产总值,重载友元重载运算符号(+)和(>)为计算生产总值和产值比较。代码如下:

#include <iostream>

#include<math.h>

#include<iomanip.h>

class crops

{

int output,area; //单产(公斤)、种植面积(亩)

double total;   //生产总值

public:

crops(char *crops_name);

double gettotal()    //返回生产总值

{

return total;

}

void dispTotal() //显示生产总值

{

cout<<setiosflags(ios::fixed)<<setprecision(2)<<total<<endl;

}

friend double operator+(crops t1,crops t2) //友元重载运算符号+

{

return t1.total+t2.total;

}

friend double operator+(double a,crops t) //友元重载运算符号+

{

return  a+t.total;

}

friend bool operator>(crops t1,crops t2)   //友元重载运算符号>

{

return t1.total>t2.total ?true:false;

}

~crops()

{

}

};

crops::crops(char *crops_name) //构造函数

{

int i,j;

cout<<"请输入"<<crops_name<<"单产(公斤)和:种植面积(亩)"<<endl;

cin>>i>>j;

if(i>0 &&j>0)  //输入大于0

total=i*j;

else

{

cout<<"注意!输入的输入为0"<<endl;

total=output=area=0;

}

}

void main()

{

crops t1("小麦"),t2("玉米"),t3("油菜");  //调用构造函数声明crops变量t1t2t3

cout<<"小麦产生产总值:";t1.dispTotal();  //信息输出

cout<<"玉米产生产总值:";t2.dispTotal();

cout<<"油菜产生产总值:";t3.dispTotal();

if(t1>t2)  //调用友元重载运算符号>

cout<<"小麦比玉米多:"

<<t1.gettotal()-t2.gettotal()<<endl;

else

    cout<<"玉米比小麦多:"

<<t2.gettotal()-t1.gettotal()<<endl;

cout<<"总生产总值:"<<t1+t2+t3<<endl;    //调用友元重载运算符号+

system("pause");

}

【案例分析】

1friend double operator+()为友元函数重载运算符,需要在类体内进行声明,在前面加上关键字friend。友元函数不是成员函数,但其的用法也与普通的函数完全一致,不同的是能访问类中所有的数据。友元函数破坏了类的封装性和隐蔽性,使得非成员函数可以访问类的私有成员。一个类的友元可以自由地用该类中的所有成员。友元函数不带有this指针,因此必须将对象名或对象的引用作为友元函数的参数,这样才能访问到对象的成员。

2)重载运算符与一般函数的比较:相同点1)均为类的成员函数,2)实现同一功能。当用成员函数实现运算符的重载时,运算符重载函数的参数只能有二种情况:没有参数或带有一个参数。对于只有一个操作数的运算符(如++),在重载这种运算符时,通常不能有参数;而对于有二个操作数的运算符,只能带有一个参数,这参数可以是对象,对象的引用,或其他类型的参数。在C++中不允许重载有3个操作数的运算符。

 

提示:友元函数与一般函数的不同点:友元函数必须在类的定义中说明,其函数体可在类内定义,也可在类外定义;它可以访问该类中的所有成员(公有的、私有的和保护的),而一般函数只能访问类中的公有成员。

案例10-6  回合制对战小游戏

【实例描述】

大型游戏开发中,可利用面向对象的编程技术如友元、多态的纯虚函数等技术,实现游戏复杂的功能,本实例是一个回合制游戏的模型。本例效果如图10-6所示。

【实现过程】

定义任务物品栏类container。定义一个玩家类Player,玩家分3种职业Swordsman、Archer和Mage。部分代码实现如下:

class container //任务物品栏

{

protected:

int numOfHeal; //恢复药水数目

int numOfMagicWater; //魔法药水数目

public:

container();

void set(int i,int j); //清零

int nOfHeal(); //返回生命值

int nOfMW(); //返回魔法值

void display(); //显示信息

bool useHeal();

bool useMW(); //使用了魔法药水,魔法增加

};

container::container()

{

set(0,0);

}

void container::set(int i,int j) //清零

{

numOfHeal=i; //恢复药水数目

numOfMagicWater=j; //魔法药水数目

}

int container::nOfHeal() //返回生命值

{

return numOfHeal;

}

int container::nOfMW() //返回魔法值

{

return numOfMagicWater;

}

void container::display() //显示信息

{

cout<<"恢复药水(生命值+100)还有"<<numOfHeal<<""<<endl;

cout<<"魔法药水(魔法值+80)还有"<<numOfMagicWater<<""<<endl;

}

bool container::useHeal()

{

numOfHeal--; //恢复药水数目

return 1;

}

bool container::useMW()

{

numOfMagicWater--; //魔法药水数目

return 1;

}

enum property{sw,ar,mg}; //三种职业

class Player

{

friend void showinfo(Player &p1,Player &p2);//待补充

friend class Swordsman; //定义友元类:剑士

friend class Archer; //定义友元类:弓箭手

friend class Mage; //定义友元类:法师

protected://

int HP,HPmax,MP,MPmax,AP,DP,speed,EXP,LV;

char name[10];

property role;

container bag;

public:

virtual bool attack(Player &p)=0;//普通攻击

virtual bool specialatt(Player &p)=0;//特殊攻击

virtual void isLevelUp()=0; //升级设定

void ReFill();

bool Death();

void isDead();

bool useHeal();

bool useMW();

void transfer(Player &p); //杀死敌人后,玩家获得对方物品

char showRole();

//待补充

bool death;

};

【案例分析】

1)回合制网游,就是指在游戏中遇到怪物时转到战斗界面,敌我方在左、右两边,我一下他一下的打斗,直至战斗结束返回正常的游戏,界面的游戏方式。游戏节奏较慢,玩家可以边玩边聊天。游戏操作简单,可以加入包括宠物、召唤兽等复杂的系统,玩家可以同时操作多个角色;游戏的PK较为轻松,玩家把战斗当作是一种娱乐,而不是发泄。

2)类Swordsman是类Player的友元。对于类Swordsman而言,类Player是透明的。类Swordsman必须通过类Player的对象使用类Player的成员,类Swordsman中的任何函数都能使用类Player中的所有私有成员。如果在一个派生类中要访问基类中的私有成员,可以将这个派生类声明为基类的友元。类Player为抽象类,该类代码还定义几个虚函数attack、specialatt和isLevelUp。

 

提示:记住:友元关系是不能传递的,友元关系是单向的,友元关系是不被继承的。

案例10-7  十二星座运气测试

【实例描述】

游戏编程中常涉及到类和命名空间知识、文件输入和输出、友元函数等。本实例讨论输入出生月日求星座运气的问题,效果如图10-7所示。

 

10-7  十二星座运气测试

【实现过程】

C++语言编写的一个简单的星座程序,可以根据用户输入的生日数据来查找用户的星座和星座的相关信息。代码实现如下:

namespace constellation_james

{

class Birthday //生日类

{

public:

Birthday();

int get_month(); //取得月

int get_day(); //取得日

void inter_face(); //提示

void input_date(istream& ins); //输入生日

void check_date(); //输入生日是否合规则

friend void count_constellation(Birthday& date); //占卜

friend string get_in_file_name(Birthday& date); //打开对应文件内容

private:

int month;

int day;

};  

}

#endif

using namespace std;   

namespace constellation_james   

{   

    int flag;   

   

    Birthday::Birthday() : month(1), day(1)   

    {   

     

    }   

    int Birthday::get_month() //取得月

    {   

        return month;   

    }   

    int Birthday::get_day()    //取得日

    {   

        return day;   

    }  

【案例分析】

1C++对文件的输入输出需要用到ifstreamofstream类。ifstream支持对文件输入的操作,ofstream支持对文件输出的操作。友元函数是一种定义在类外部的普通函数,其特点是能够通过对象名访问类中私有成员和保护成员,即类的访问权限的限制对其不起作用。

2)代码是C++开发的算命小游戏,通过输入出生年月就可计算出你的星座,并对相关命运进行提示。代码中提供一个全局的命名空间namespace,可以避免全局命名冲突问题。

 

提示:相关星座分析文本仅供参考,供娱乐而已。

10.5  运算符重载

案例10-8  使用C++字符串类string打印字符串

【实例描述】

本实例是简单处理C++字符串类的小程序,类string是字符串的一种,例如,其中存储的是字符串帮助提示信息,要显示出来,用cout就可以简单做到。本例运行效果如图10-8所示。

 

 

10-8  使用C++字符串类string打印字符串

【实现过程】

定义一个C++字符串类String,定义成员函数分别是运算符重载+”,返回字符串的长度String(),打印字符串show_string()和连接两个字符串append()。其代码如下:

#include <iostream>

#include <iomanip>

#include <string.h>

using namespace std;

class String {

  public:

    char *operator +(char *append_str) //运算符重载“+”,连接两个字符串

    {

       return(strcat(buffer, append_str));

    };

   

    String(char *string)

    {

    strcpy(buffer, string);

        length = strlen(buffer); //返回字符串的长度运算符

  }

    void show_string(void)

{

cout << buffer; //打印字符串

};

  

    void append(char *source)

{

strcat(buffer, source); //连接两个字符串

};

 

  private:

    char buffer[256];

    int length;

};

int main(void)

{

   String title("C++"); //定义一个字符串类

   title = title + "字符串类string\n";

   title.show_string(); //打印字符串

   cout<<endl;

   String book2("打印"); //定义一个字符串类

   book2.append("字符串");

   book2.show_string(); //打印字符串

   cout<<endl;

   system("pause");

}

【案例分析】

1)字符串实际上就是一串连续的字符序列,所以也可以用简单的字符数组来表示它。代码char stdn[N][15];,存储N个最长15个字符的二维数组,字符串中有效内容的结尾处加一个空字符表示字符结束,它的常量表示可写为0'\0'

2)上面的代码定义一个字符串类String,封装几个成员函数运算符重载“+”,返回字符串的长度运算符String(char *string) 等,C++类的基本应用将在第7章详细介绍。

 

提示:与普通数据类型不同的一点是,要想声明和使用字符串类型的变量,需要引用头文件<string>,并且使用using namespace语句来使用标准名空间(std)。

10.6  类型转换

案例10-9  使用成员函数检测string字符串是否非空

【案例描述】

实现编程中,登录用户名常是一个string字符串,需获取登录用户名时,如果返回的字符串非空,则说明这个用户存在。本例与10-8实例类型类似,涉及到第9章类的概念,实例中需要把功能封装起来,定义成员函数来检测string字符串是否非空。本例效果如图4-15所示。

 

10-9  使用成员函数检测string字符串是否非空

【实现过程】

定义字符串类String,类中定义成员函数empty(),其功能是检测string字符串是否为非空,其他成员功能与060实例类型类似,实现连接两个字符串。代码实现如下:

#include <iostream>

#include <iomanip>

#include <string>

using namespace std;

class String {

  public:

    char *operator +(char *append_str) //运算符重载‘“+’”,,连接两个字符串

    {

       return(strcat(buffer, append_str));

    };

    String(char *string)

    {

    strcpy(buffer, string);

        length = strlen(buffer); //返回字符串的长度运算符

  }

    void show_string(void)

{

cout << buffer; //打印字符串

};

  

    void append(char *source)

{

strcat(buffer, source); //连接两个字符串

};

     void empty(string source)

{

     cout << "\n\n测试字符串是否为空" << endl;

     if ( source.empty() )

        cout << "字符串为空" << endl;

     else {

       cout << "字符串为 is \"" << source << "\""<<endl;

   cout << "字符串不为空"<<endl;

}

      }

  private:

    char buffer[256];

    int length;

};

int main(void)

{

   String title("C++"); //定义一个字符串类

   title = title + "字符串类string\n";

   title.show_string(); //打印字符串

   cout<<endl;

   String book("打印"); //定义一个字符串类

   book.append("字符串");

   book.show_string(); //打印字符串

   cout<<endl;

   char *source1="",*source2="test";

   book.empty(source1);  //检测string字符串是否为非空

   book.empty(source2);

   system("pause");

   return 1;

}

【案例分析】

1)代码source.empty()的原型为bool empty() const;,其功能是检查字符串是否为非空。

2String定义为处理字符串的类,里面有运算符重载‘“+’”,*operator +为连接两个字符串成员函数,strlen(buffer);返回字符串buffer[256]的长度。strcat(buffer, source); 连接两个字符串buffer[256]和char *source。

 

注意:C++语言中类的概念非常重要,本实例提到的类模板的概念会将在第8章详细介绍。

10.7  重载函数选择规则

案例10-10  函数重载陷阱实例

【实例描述】

本实例继续讨论函数重载,使用函数重载要注意什么,什么情况会发现错误,如定义函数print(int)再定义函数print(float),这时程序中加入代码print(1.8),编译的时候就会出现错误。本例效果如图10-10所示。

 

10-10  函数重载陷阱实例

【实现过程】

程序分4个演示,k(int n1,int n2),k(int n,int n1) 传入参数的类型和个数相同;print(int n)和print(float p)传入参数的类型不同但个数相同。代码实现如下:

#include <iostream>

using namespace std;

int main()

{

void print(int); //函数声明

void print(float); //函数声明

     void k(int n1,int n2);

     long k(int n,int n1);

print(1.8);

k(30,2);

cout<<"5!阶乘=";

cout<<k(5,1);

/*  正确

  void print(int); //函数声明

void print(float); //函数声明

    void k(int n1,int n2);

    long k(int n,int n1,int n2); //正确,重载函数需要参数个数或类型不同

k(30,2);

cout<<"5!阶乘=";

cout<<k(5,1,1)<<endl;

print(int(1.8)); //正确,显式样转换

print(float(1.8)); //正确,显式样转换

*/

system("pause");

return 0;

}

void k(int n1,int n2)  //两个整数相乘

{

long s=1;

s=n1*n2;

cout<<"两个整数相乘"<<n1<<"*"<<n2<<"=";

cout<<s<<endl;

}

long k(int n,int n1) //递归函数

{

float f;

if(n<0)

{

  //如果输入负数,报错并以-1作为返回值

      cout<<"n<0,负数不能做阶乘计算!"<<endl;

      f=-1;

}

else if (n==0||n==1) f=1; //0!1!的值为1

else f=k(n-1,1)*n; //n>1时,进行递归调用

return f; //f的值作为函数值返回

}

/*

long k(int n,int n1,int n2) //正确,递归函数

{

float f;

if(n<0)

{

 //如果输入负数,报错并以-1作为返回值

      cout<<"n<0,负数不能做阶乘计算!"<<endl;

      f=-1;

}

else if (n==0||n==1) f=1; //0!1!的值都为1

else f=k(n-1,1,1)*n; //n>1时,进行递归调用

return f; //f的值作为函数值返回

}

*/

void print(int n) //print函数定义,参数为int

{

cout<<"整数:"<<n<<endl;

}

void print(float p) //print函数定义,参数为float

{

cout<<"浮点数:"<<p<<endl;

}

【案例分析】

1)调用函数重载,如果实参类型与形参类型不匹配,编译器会对实参自动进行类型转型。如果转换后仍然不能匹配到重载的函数,这时产生一个编译错误。如代码print(1.8);,编译器就不能判断是转换成int还是float

2)代码中定义函数void k(int n1,int n2),再定义函数long k(int n,int n1),就会出现函数定义上的错误。关于重载一定要提示:重载函数的参数类型和参数个数一定要不同(要么参数的类型不同,要么参数的个数不同,要么参数的类型和个数都不同)。否则,编译器就不知道该调用那个函数了。

 

提示:函数重载在类和对象应用比较多,尤其是在类的多态性中。在以后将碰到更多的在类型不同的函数重载,尤其是在结合类的继承性和指针类型的不同,而这些都是以后用VC++编程中经常要用到的。

10.8  实体的作用域和可见域

案例10-11  作用域

【实例描述】

变量是有有效范围变量的有效作用域从它的定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号。也就是说,作用域由变量所在的最近一对括号确定。根据作用域的范围不同分为全局变量、局部变量、 寄存器变量、 寄存器变量、 寄存器变量、const常量和volatile变量。本例效果如图10-11所示。

 

10-11  作用域

【实现过程】

本案例是演示显示同名变量可见性的例子,全局变量n=100,外部变量i=200,j=300,内部变量int i=500,j=600,。分别输出演示的结果。代码实现如下:

#include<iostream>

using namespace std;

int n=100;

int main(){

     int i=200,j=300;

     cout<< n<<'\t'<<i<<'\t'<<j<<endl;{      //输出全局变量n和外层局部变量i,j

         int i=500,j=600,n;                      //内层块

         n=i+j;

         cout<< n<<'\t'<<i<<'\t'<<j<< endl; //输出内层局部变量ni,j

         cout<<::n<<endl;                        //输出全局变量n

     }

     n=i+j;                                        //修改全局变量

     cout<< n<<'\t'<<i<<'\t'<<j<< endl;     //输出全局变量n和外层局部变量i,j

     return 0; }

【案例分析】

1块指一对大括号括起来的程序段。块中定义的标识符,作用域在块内

2函数原型不是定义函数。在作函数原型声明时,其中的形参作用域只在原型声明中,即作用域结束于右括号。正是由于形参不能被程序的其他地方引用,所以通常只要声明形参个数和类型,形参名可省略。如函数原型作用域void swap(int,int);

3文件作用域也称全局作用域 定义在所有函数之外的标识符,具有文件作用域,作用域为从定义处到整个源文件结束。

10.9  名称空间的作用域和可见域

案例10-12  名称空间的作用域和可见域

【实例描述】

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突。本例效果如图10-12所示。

 

10-12  名称空间的作用域和可见域

【实现过程】

using namespace std是指使用C++自己的名称空间,即std在命名空间中声明的标识符是可以被直接引用的,不需要任何的命名空间的修饰符。然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。代码实现如下:

#include <iostream>

namespace CounterNameSpace

{

 

    int upperbound;

    int lowerbound;

 

    class counter

    {

 

     int count;

     public:

     counter(int n)

     {

 

            if ( n <= upperbound ){

                count = n;

            } else  {

                count = upperbound;

            }

      }

    void reset(int n)

     {

       if ( n < upperbound )

            {

                count = n;

            }

        }

     int run() {

      if ( count > lowerbound)

       {

                return count--;

       } else {

                return lowerbound;

       }

      }

    };

}

int main()

{

   CounterNameSpace  counter obj; // 非法,没有定义ColorTable!

   obj.count=1;

   return 1;

}

【案例分析】

1如果没有命名空间,这些变量、函数、类的名称将都存在于全局命名空间中,会导致很多冲突

2相同的空间名称是可以被多次声明的,这种声明向相互补充的,这就使得命名空间可以被分割到几个文件中甚至是同一个文件的不同地方中。

10.10 本章练习

 

原创粉丝点击