3.1 结构与类
3.1.1 C++对结构的扩展
最初的C++称为“带类的C”,扩展了C语言结构的功能。C++中的结构不仅可以包含数据,而且可以包含操作这些数据的函数。将数据和操作数据的函数包装在一起的主要目的是实现数据封装和信息隐藏,信息隐藏就是使结构中的数据和对数据进行操作的细节对外不可见。简单地说,信息隐藏就是不让结构外部的函数直接修改结构中的数据,只能通过结构的成员函数对数据进行间接修改。为了实现信息隐藏,限制对结构某些成员的非法访问,C++增设了以下三个访问权限限定符,用于设置结构中数据成员和成员函数的访问权限。
① public:被设置为public权限的成员(包括数据成员和成员函数)称为类的公有成员,可被任何函数访问(包括结构内和结构外的函数)。public区域中的成员称为类的接口。
② private:被设置为private权限的成员(包括数据成员和成员函数)称为类的私有成员,只能被结构内部的成员访问。
③ protected:与继承有关,以后再介绍。
C++默认结构成员都具有public权限,可被直接访问,通过访问控制权限的设置,可以改变C++结构中成员的访问权限。
【例3-1】 一个包含了数据和数据操作函数的复数结构。
//Eg3-1.cpp #include <iostream> using namespace std; struct Complex{ private: double r; double i; public: void init(double rr,double ii){r=rr;i=ii;} double real() {return r;} double image() {return i;} }; void main(){ Complex a; a.init(2,3); cout<<a.real()<<"+"<<a.image()<<"i"<<endl; a.r=6; //L1 错误 a.i=3.2; //L2 错误 }
访问权限限定符的有效范围是从其开始直到下一个权限设置。所以本例中的private将数据成员r和i都设置成了private权限,public则将init()、real()和image()三个成员函数设置为public权限。因此,r和i只能被Complex内部的成员函数init()、real()和image()访问,而函数init()、real()和image()则可被结构之外的任何函数访问。
main( )中对a.r和a.i的直接赋值是错误的,因为r和i是Complex结构内部的私有成员,不允许main()函数直接访问它们,a.r和a.i的修改只能通过public成员函数init()进行:
3.1.2 类
struct将所有成员都默认为public权限,这很不安全。如果在设计结构时,本想将成员设置为private权限,但因疏忽而忘了加上关键字private,成员就变成公有权限了。此外,struct还容易与传统C语言中的结构混淆。基于这些原因,C++引进了功能与struct相同但更安全的数据类型——类。
类也是一种自定义数据类型,用关键字class表示,用法与struct相同,形式如下:
class class_name{ [private:] //可以省略 data_member; functin_name; public: data_member; functin_name; protected: data_member; functin_name; }; //分号必不可少
class_name是类名,常用首字符大字的标识符表示;private、public、protected用于指定成员的访问权限,与其在struct中的含义和用法都相同;data_member表示数据成员;functin_name表示成员函数;一对“{}”表示类的范围,“}”后面的分号必不可少,表示类声明的结束。
【例3-2】 用class定义的复数类Complex。
//Eg3-2.cpp #include <iostream.h> class Complex{ private: double r; double i; public: void init(double rr,double ii){r=rr;i=ii;} double real() {return r;} double image() {return i;} }; void main(){ Complex a; a.init(2,3); cout<<a.real()<<"+"<<a.image()<<"i"<<endl; a.r=6; //错误,访问类的私有成员 a.i=3.2; //错误,访问类的私有成员 }
说明:① 类声明中的访问限定符private、public、protected没有先后次序之分,哪个在前面,哪个在后面没有区别,常将private成员的声明放在类的后面,将public成员放在前面,以方便人们了解类的可访问接口。
② 在同一个类中,访问限定符private、public、protected的出现次数没有限制。例如,可以将一个public区域中的成员分散为多个public区域,也可以将多个public区域中的成员合并在一个public区域中。
③ 数据成员和成员函数都可以设置为public、private或protected属性。出于信息隐藏的目的,常将数据成员和只能让类内部访问的成员函数设置为private权限,将需要让类的外部函数(非本类定义的函数)访问的成员函数设置为public权限,
④ 数据成员可以是任何数据类型,如整型、浮点型、字符型、数组、指针、引用等,也可以是另外一个类的对象或指向对象的指针,还可以是指向自身类的指针或引用,但不能是自身类的对象。数据成员不能指定为自动(auto)、寄存器(register)和外部(extern)存储类型。例如:
class A{……}; class B{ private: int a; A obja1; //正确 A *obja2; //正确 B *objb,&objr; //正确 B b1; //错误 auto int b; //错误 extern int c; //错误 public: …… };
⑤ 在声明(或定义)类时,不能为数据成员赋初值。例如:
class A{ private: int a=0; //错误 int b[3]={1,2,3}; //错误 public: …… };
类的声明(或定义)只是增加了一种自定义数据类型,不存在为数据成员分配存储空间的事情。在声明(或定义)类时就为数据成员赋初值是错误的,因为此时数据成员在内存中还不存在。只有用类定义变量时,才会为类变量分配存储空间,数据成员才会在内存中存在。
⑥ C++的struct也是一种类,它与class具有相同功能,用法完全相同。struct与class的唯一区别是,在没有指定成员的访问权限时,struct中的成员具有public权限,而class中的成员则具有private权限。例如:
struct Complex{ class Complex{ double r; double r; double i; double i; public: public: …… …… }; };
struct Complex中的r和i是public成员,而class Complex中的r和i则是private成员。
虽然struct和class具有同样的功能,但在实际工作中,常用class设计具有成员函数的类,而struct则保留C语言中的用法,常用来设计只包含数据成员的结构。