1.类和对象
C++程序是由许多类所构成的,类是C++的灵魂。
程序=算法+数据结构
类是对象的抽象,而对象是类的具体实例。
对于类体内定义的函数,一般都省写inline,如果成员函数不在类体内定义,而在类体外定义,系统并不把它默认为内置(inline)函数。
如果在类体外定义inline函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中)。
每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函数代码所占用的存储空间。
p->hour表示p当前所指向的对象t中的成员hour,(*p).hour也是对象t中的成员hour,因为(*p)就是对象t。在p指向t的前提下,p->hour,(*p).hour和t.hour三者等价。
类是一种抽象的数据类型,并不是一个实体,也不占存储空间,而对象是实际存在的实体,是占存储空间的,其数据成员是有值的,可以被引用的。
如果在类的定义中既不指定private,也不制定public,则系统就默认认为是私有的。
当接口与实现(对数据的操作)分离时,只要类的接口没有改变,对私有实现的修改不会影响程序的其他部分。
类声明头文件就成为用户使用类库的有效方法和公用接口。
包含成员函数定义的文件就是类的实现。
2.关于类和对象的进一步讨论
构造函数来处理对象的初始化。构造函数的名字必须与类名同名,不具有任何类型,不返回任何值。
构造函数的赋值语句是写在构造函数函数体中的,只有在调用构造函数时才执行这些赋值语句,为当前的对象中的数据成员赋值。
构造函数不需用户调用,也不能被用户调用。
在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句,但是一般不提倡在构造函数中加入与初始化无关的内容。
如果用户自己没有定义构造函数,C++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。
带参数的构造函数中的形参,其对应的实参在定义对象时给定。用这种方法可以方便地实现对不同的对象进行不同的初始化。
还可以使用参数初始化表来实现对数据成员的初始化,例如:
Box::Box(int h,int w,int l):height(h),width(w),length(l){ }
可以定义多个构造函数,但是形参不能相同,编译系统是根据函数调用的形式来确定对应的函数的。
在调用构造函数时不必给出实参的构造函数,称为默认构造函数,一个类只能有一个默认构造函数否则,系统就无法辨别应执行哪个构造函数。
尽管在一个类中可以包含多个构造函数,但是对每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行。
在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
析构函数也是一个特殊的成员函数,对象生命周期结束时会自动执行析构函数。
static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
析构函数不返回任何值,没有函数类型,也没有函数参数。由于没有函数参数,它不嗯给你被重载。一个类可以有多个构造函数,但是只能有一个析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。它还可以被用来执行“用户希望在最后一次使用对象之后所执行的任何操作”。想让析构函数完成任何工作,都必须在定义的析构函数中指定。
先构造的后析构,后构造的先析构(越早被创建,对象越早被撤销。)
数组不仅可以由简单变量组成,也可以由对象组成。
在建立数组时,同样要调用构造函数。在需要时可以在定义数组时提供实参以实现初始化。如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供实参。
编译系统只为每个对象元素的构造函数传递一个实参,所以在定义数组时提供的实参个数不能超过数组元素个数。
在建立对象数组时,分别调用构造函数,对每个元素初始化。每一个元素的实参分别用括号包起来,对应构造函数的一组形参,不会混淆。
指针可以用来指向一般的变量,也可以指向对象。
对象空间的起始地址就是对象的指针。
在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,成为this。它是指向本类对象的指针。它的值是当前被调用的成员函数所在的对象的起始地址。
this指针是隐式使用的,它是作为参数被传递给成员函数的。
如果一个对象被声明为常对象,则不鞥呢调用该对象的非const型成员函数。
把函数声明为可变的数据成员(mutable int count;),就可以用声明为const的成员函数来修改它的值。
常数据成员只能通过构造函数的参数初始化表对常数据成员进行初始化。如:
const int hour;
Time::Time(int h):hour(h){}
如果要求所有的数据成员的值都不允许改变,则可以将所有的数据成员声明为const,或将对象声明为const(常对象),然后用const成员函数引用数据成员,这样起到“双保险”的作用,切实保证了数据成员不被修改。
常成员函数不能调用另一个非const成员函数。
指针变量声明为const型并将之初始化,这样指针值始终保持为其初值,不能改变,即其指向始终不变。ru
Time t1(10,12,15),t2;
Time *const ptr1=&t1;
ptr1=&t2; //错误,ptr1不能改变指向
定义指向对象的常指针的一般形式为
类名 *const指针变量名=对象地址;
Time *const ptr1=&t1;
定义常变量的指针变量的一般形式为
const 类型名 *指针变量名;
如果一个变量已被声明为常变量,只能用指向常变量的指针变量指向它。
可以用new运算符动态建立对象,用delete运算符撤销对象。
new Box;
编译系统开辟了一段内存空间,并在此内存空间中存放一个Box类对象,同时调用该类的构造函数,以使该对象初始化。但是无法访问,因为没有名字。称为无名对象,存在但没有名字。
用new运算符动态地分配内存后,将返回一个指向新对象的指针的值,即所分配的内存空间的起始地址。
C++还允许在执行new时,对新建立的对象进行初始化。
Box *pt=new Box(12,15,18);
调用对象既可以通过对象名,也可以通过指针。
在不再需要使用由new建立的对象时,可以用delete运算符予以释放。如
delete pt;
对象之间的赋值也是通过赋值运算符“=”进行的,本来赋值运算符“=”只能用来对单个的变量赋值,现在被扩展为两个同类对象之间的赋值,这是通过对赋值运算符的重载实现的。
一般形式为
对象名1=对象名2
对象的赋值只能堆其中的数据成员赋值,而不能对成员函数赋值。
类的数据成员中不能包括动态分配的数据。
对象的赋值,形式为
类名 对象2(对象1);
复制构造函数也是构造函数,但它只有一个参数,这个参数是本类的对象,而且采用对象的引用的形式(一般约定加const声明,使参数值不能改变,以免在调用此函数时因不慎而使对象值被修改)。此复制构造函数的作用就是将实参对象的各数据成员值一一赋给新的对象中对应的数据成员。
C++还提供另一种方便用户的复制形式,用赋值号代替括号。其一般形式为
类名 对象名1=对象名2;
对象的赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的赋值则是从无到有地建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)。
如果想在同类的多个对象之间实现数据共享,也不要用全局对象,可以用静态的数据成员。静态的数据成员在内存中只占一份空间,每个对象都可以引用这个静态数据成员。只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间,它可以被引用。在一个类中可以有一个或多个静态数据成员。
静态数据成员可以初始化,但只能在类体外进行初始化。形式为:
数据类型 类名::静态数据成员名=初值;
注意:不能用参数初始化表对静态数据成员初始化。
将变量定义为公用的静态数据成员,所以在类外可以直接引用。如果静态数据成员被定义为私有的,则不能在类外直接引用,而必须通过公用的成员函数引用。
同理,成员函数也可以定义为静态的。与静态数据成员不同,静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员。
静态成员函数与非静态成员函数的根本区别是:非静态成员函数有this指针,而静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。
静态成员函数可以直接引用本类中的静态数据成员,因为静态数据成员同样是属于类的,可以直接引用,静态成员函数主要用来访问静态数据成员,而不访问静态成员。并不是绝对不能引用本类中的非静态成员,只是不能进行默认访问。如果一定要引用本类的非静态成员,应该加对象名和成员运算符“.”。
友元可以访问与其有好友关系的类中的私有成员。友元包括友元函数和友元类。
如果在本来以外的其他地方定义了一个函数(这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在本类进行声明时在类体中用friend对该函数进行声明,此函数就称为本类的友元函数。
如果在类的定义体中未声明display函数为friend函数,它是不能引用Time中的私有成员的,但注意引用这些私有数据成员时,必须加上对象名,因为display函数不是Time类的成员函数,不能默认引用Time类的数据成员,必须指定要访问的对象。
类的提前声明的使用范围是有限的,只有在正式声明一个类以后才能用它去定义类对象。
一个函数(包括普通函数和成员函数)可以被多个类声明为“朋友”,这样就可以引用多个类中的私有成员。
将一个类(B)声明为另一个类(A)的“朋友”,这时B类就是A类的友元类,友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。声明友元类的一般形式为
friend 类名;
友元的关系是单向的不是双向的,友元的关系不能传递,工作中,除非确实有必要,一般并不把整个类声明为友元类。
可以定义一个可对任何类型变量进行操作的函数模板。
template 类模板是类的抽象,类是类模板的实例。 3.运算符的重载 运算符重载实质上是函数的重载。一般格式为 函数类型 operator 运算符名称 (形参表列) {对运算符的重载处理} operator+是一个函数名。 运算符被重载后,其原有的功能仍然保留,没有丧失或改变。 C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。不能重载的运算符只有5个(“.”,“.*”,“::”,“sizeof”,“?:”) 重载不能改变运算符运算对象的个数。重载不能改变运算符的结合性。重载运算符的函数不能有默认的参数。重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个类对象(或类对象的引用)。 用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”不必用户重载。 应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能。 运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数。 将双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数,不能省略,形参的顺序任意,不要求第一个参数,必须为类对象,但在使用运算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。(数学上的交换律不适用,如果希望适用交换律则应再重载一次运算符“+”。 先搭框架,逐步扩充,由简到繁,最后完善。边编程,边调试,边扩充。 由于单目运算符只有一个操作数,因此运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。 前置自增运算符“++”和后置自增运算符“++”二者作用的区别。前者是先自加,返回的是修改后的对象本身。后者返回的是自加前的对象,然后对象自加。 用户自己定义的类型的数据,是不能直接用“<<”和“>>”来输入输出的。如果想用它们输入输出自己声明的类型的数据,必须对它们进行重载。形式如下: istream & operator>>(istream &,自定义类&); ostream & operator<<(ostream &,自定义类&); 即重载运算符>>的函数的第一个参数和函数的类型都必须是istream& 类型,第二个参数是遥进行输入操作的类。重载<<的函数的第一个参数核函数的类型都比现实ostream& 类型,第二个参数是要进行输出操作的类。只能将重载>>和<<的函数作为友元函数或普通的函数,而不能将它们定义为成员函数。 4.继承与派生 面向对象程序设计的四个主要特点:抽象、封装、继承和多态性。 所谓继承就是在一个已存在的类的基础上建立一个新的类。 声明派生类的一般形式为: class 派生类名:[继承方式] 基类名 { 派生类新增加的成员 }; 无论哪一种继承方式,在派生类中是不能访问基类的私有成员的,私有成员只能被本类的成员函数所访问。 在执行派生类的构造函数时,调用基类的构造函数。 派生类构造函数首行的写法: 派生类构造函数名(总参数表列):基类构造函数名(参数表列) {派生类中新增数据成员初始化语句} 派生类构造函数的任务包括三部分: 1.对基类数据成员初始化; 2.对子对象数据成员初始化; 3.对派生类数据成员初始化。 如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。 在引用这些同名的成员时,必须在派生类对象名后增加直接基类名,以避免产生二义性,使其唯一地标识一个成员。 虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的,因为一个基类可以在生成一个派生类时不作为虚基类。声明虚基类的一般形式为: class 派生类名:virtual 继承方式 基类名 为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。 如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类中,通过构造函数的初始化表对虚基类进行初始化。 在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。 只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能。 不同类型数据之间的自动转换和赋值,称为赋值兼容。基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。 (1)派生类对象可以向基类对象赋值。 (2)派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化。 (3)如果函数带参数是基类对象或基类对象的引用,相应的实参可以用子类对象。 (4)派生类对象的地址可以赋给指向基类对象的指针变量,也就是说,指向基类对象的指针变量也可以指向派生类对象。 在一个类中以另一该类的对象作为数据成员的,称为类的组合。 继承是纵向的,组合是横向的。 如果修改了成员类的部分内容,只要成员类的公用接口不变,组合类可以不修改。但组合类需要重新编译。 5.多态性与虚函数 多态性是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的方法,也就是说每个对象可以用自己的方式去相应共同的消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。 派生类对象可以替代基类对象为基类的引用初始化或赋值。 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。 虚函数的使用方法是: (1)在基类用virtual声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便的地被调用。 在类外定义虚函数时,不必加virtual。 (2)在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。 当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此在派生类重新声明该虚函数时,可以加virtual,也可以不加,但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰。 如果在派生类中没有对基类的虚函数重新定义,则派生类简单地继承其直接基类的虚函数。 (3)定义一个指向基类对象的指针变量,并使它指向同一类族中的某一对象。 (4)通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。 确定调用的具体对象的过程称为关联。指把一个函数名与一个类对象捆绑在一起,建立关联。关联指把一个标示符和一个存储地址联系起来。 在编译时即可确定其调用的虚函数属于哪一个类,其过程称为静态关联,也称早期关联。函数重载属于静态关联。 在运行阶段把虚函数和类对象“绑定”在一起的过程称为动态关联。也称为滞后关联。 什么情况下应当声明虚函数 (1)只能用virtual声明类的成员函数,使它称为虚函数,而不能将类外的普通函数声明为虚函数。 (2)一个成员函数被声明为虚函数后,在同意类族中的类就不能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数。 根据什么考虑是否把一个成员函数声明为虚函数呢? (1)首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。 (2)如果成员函数所在的类继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。 (3)应考虑成员函数的调用是通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问的,则应当声明为虚函数。 (4)有时,在定义虚函数时,并不定义其函数体,即函数体是空的。它的作用只是定义了一个虚函数名,具体功能留给派生类去添加。 使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放每个虚函数的入口地址。 纯虚函数是在声明虚函数时被“初始化”为0的函数。一般形式为: virtual 函数类型 函数名 (参数表列)=0; 注意:纯虚函数没有函数体;最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉便以系统“这是纯虚函数”;这是一个声明语句,最后应有分号。 纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。如果在基类中没有保留函数名字,则无法实现多态性。 如果一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。 不用来定义对象而只作为一种基本类型用作继承的类,称为抽象类,由于它常用作基类,通常称为抽象基类。凡是包含纯虚函数的类都是抽象类。因为纯虚函数是不能被调用的包含纯虚函数的类是无法建立对象的,抽象类的作用是作为一个类族的共同基类,或者说,为一个类族提供一个公共接口。 一个类层次结构中当然也可以不包含任何抽象类,每一层次的类都是实际可用的,都是可以用来建立对象的。 虽然抽象类不能定义对象,但是可以定义指向抽象类数据的指针变量。当派生类称为具体类之后,就可以用这种指针指向派生类对象,然后通过该指针调用虚函数,实现多态性的操作。 6.输入输出流 对系统指定的标准设备的输入和输出,即从键盘输入数据,输出到显示器屏幕。这种输入输出称为标准的输入输出,简称标准I/O。以外存磁盘文件为对象进行输入和输出称为文件的输入输出,简称文件I/O。对内存中指定的空间进行输入和输出通常指定一个字符数据作为存储空间,这种输入输出称为字符串输入输出,简称串I/O。 C++的I/O操作是类型安全的。 可扩展性是C++输入输出的重要特点之一,它能提高软件的重用性,加快软件的开发过程。 在C++中,输入输出流被定义为类。C++的I/O库中的类称为流类。用流类定义的对象称为流对象。 1.cout 流对象 cout不是C++预定义的关键字,它是ostream流类的对象,在iostream中定义。cout流中的数据时用流插入运算符“<<”顺序加入的。 cout流是容纳数据的载体,它并不是一个运算符。 用“cout<<”输出基本类型的数据时,可以不必考虑数据时什么类型,系统会判断数据的类型,并根据其类型选择调用与之匹配的运算符重载函数。 cout流在内存中对应开辟了一个缓冲区,用来存放流中的数据,当向cout流插入一个endl时,不论缓冲区是否已满,都立即输出流中的所有数据,然后插入一个换行符,并刷新流。注意如果插入一个换行符’\\n’, 则只输出a和换行,而不刷新cout流。 在iostream中只对“<<”和“>>”运算符用于标准类型数据的输入输出进行了重载,但未对用户声明的类型数据的输入输出进行重载。如果用户声明了新的类型,并希望用“<<”和”>>”运算符对其进行输入输出。 2.cerr流对象 cerr流对象是标准出错流。cerr的作用是向标准出错设备输出有关出错信息。 cout流通常是传送到显示器输出,但也可以被重定向输出到磁盘文件,而cerr流中的信息只能在显示器输出。 3.clog流对象 它的作用和cerr相同,只有一个微小的区别,cerr是不经过缓冲区,直接向显示器上输出有关信息,而clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出。 格式输出有两种方法,一种是使用控制符,另一种是使用流对象的有关成员函数。 成员函数width(n)和控制符setw(n)只对其后的第一个输出项有效。 7.C++工具 程序中常见的错误有两大类:语法错误和运行错误。语法错误又称为编译错误。 如果在执行一个函数过程中出现异常,可以不在本函数中立即处理,而是发出一个信息,传给它的上一级(即调用它的函数),它的上级捕捉到这个信息后进行处理。如果上一级的函数也不能处理,就再传给其上一级,由其上一级处理。如此逐级上送,如果到最高一级还无法处理,最后只好异常终止程序的执行。 这样做使异常的发现与处理不由同一函数来完成。好处是使底层的函数专门用于解决实际任务,而不必再承担处理异常的任务,以减轻底层函数的负担,而把处理异常的任务上移到某一层去处理。 虽然被放在try块中,并不影响它们按照原来的顺序执行。程序开始运行后,按正常的顺序执行到try块中,开始执行try块中花括号内的语句。如果在执行try块内的语句过程中没有发生异常,则catch子聚不起作用,流程转到catch子句后面的语句继续执行。如果在执行try块内的语句过程中发生异常,则throw运算符抛出一个异常信息。throw抛出异常信息后,流程立即离开本函数,转到其上一级的函数(main函数)。 throw抛出什么样的数据由程序设计者自定,可以使任何类型的数据。(包括自定义类型的数据,如类对象)。 这个异常信息提供给try-catch结构,系统会寻找与之匹配的catch子句。现在a是double型,而catch子句的括号内指定的类型也是double型,二者匹配,即catch捕获了该异常信息,这时就执行了catch子句中的语句。 由于catch子句是用来处理异常信息的,往往被称为catch异常处理块或catch异常处理器。 try-catch的结构为 try {被检查的语句} catch(异常信息类型[变量名]) {进行异常处理的语句} (1)被检测的函数必须放在try块中,否则不起作用。 (2)try块和catch块作为一个整体出现,catch块是try-catch结构中的一部分,必须紧跟try块之后,不能单独使用,在二者之间也不能插入其他语句。但是在一个try-catch结构中,可以只有try块而无catch块。即在本函数中只检查而不处理,把catch处理块放在其他函数中。 (3)try和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一个语句,也不能省略花括号。 (4)一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的异常信息匹配。 (5)catch后面的圆括号中,一般只写异常信息的类型名。catch只检查所捕获异常信息的类型,而不检查它们的值,因此如果需要检测多个不同的异常信息,应当由throw抛出不同类型的异常信息。 (6)如果在catch子句中没有指定异常信息的类型,而用了删节号“...”,则表示它可以捕捉任何类型的异常信息。这种catch子句应放在try-catch结构中的最后,相当于“其他”。如果把它作为第一个catch子句,则后面的catch子句都不起作用。 (7)try-catch结构可以与throw出现在同一个函数中,也可以不在同一函数中,也可以不在同一个函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本函数中无try-catch结构或找不到与之匹配的catch,就转到其上一层去处理,如果其上一层也无try-catch结构或找不到与之匹配的catch,则再转到更上一层的try-catch结构去处理,也就是说转到离开出现异常最近的try-catch结构去处理。 (8)在某些情况下,在throw语句中可以不包括表达式。如 throw; 表示“我不处理这个异常,请上级处理”。 (9)如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。 在不同的作用域中可以定义相同名字的变量。 全局变量的作用域 可以通过extern声明同一程序中的两个文件中的同名变量是同一个变量。 所谓命名空间,就是一个由程序设计者明明的内存区域。程序设计者可以根据需要指定一些有名字的空间域,把一些全具尸体分别放在各个命名空间中,从而与其他全局实体分隔开来。 在花括号内是声明块,在其中声明的实体称为命名空间成员。现在命名空间成员包括变量a和b,注意a和b仍然是全局变量,仅仅是把它们隐藏在指定的命名空间中而已。如果在程序中要使用变量a和b,必须加上命名空间名和作用域分辨符“::”,如ns1::a,ns1::b。这种用法称为命名空间限定,这些名字称为被限定名。 命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突。 可以根据需要设置许多个命名空间,每个命名空间代表一个不同的命名空间域,不同的命名空间不能同名。可以把不同的库中的实体放到不同的命名空间中,或者说,用不同的命名空间把不同的实体隐蔽起来。 花括号内不仅可以包括变量,而且还可以包括“变量(可以带有初始化)”,“常量”,“函数(可以是定义或声明)”,“结构体”,“类”,“模板”,“命名空间”。 如果想输出命名空间ns1中成员的数据,可以采用以下方法: cout< 引用命名空间成员的方法是: 命名空间名::命名空间成员名 可以为命名空间起一个别名,用来代替较长的命名空间。格式为: namespace 别名=命名空间名; 使用using命名空间成员名。 using声明的有效范围是从using语句开始到using所在的作用域结束。下载本文