360 likes | 557 Views
武汉大学-资源与环境科学学院-地理信息科学系. 面向对象程序设计 理论篇. By: 任福 博士 Email : renfu @ whu.edu.cn Room : 7-501. 教材及参考资料:. 《 面向对象的理论与 C++ 实践 》 王 燕 编著 清华大学出版社. 第七章:类的定义及其类对象的封装性. C++ 提供了数据结构的封装与抽象,它为程序员提供了定义新的数据类型 ——“ 类 ” 的简单而强大的工具。类本身能够控制外界对它的数据成员的访问从而避免了非授权访问操作。. 第七章:类的定义及其类对象的封装性. 以前,定义结构体类型,描述一个对象 :
E N D
武汉大学-资源与环境科学学院-地理信息科学系武汉大学-资源与环境科学学院-地理信息科学系 面向对象程序设计 理论篇 • By: 任福 博士 • Email: renfu@whu.edu.cn • Room: 7-501 教材及参考资料: 《面向对象的理论与C++实践》 王 燕 编著 清华大学出版社
第七章:类的定义及其类对象的封装性 C++提供了数据结构的封装与抽象,它为程序员提供了定义新的数据类型——“类”的简单而强大的工具。类本身能够控制外界对它的数据成员的访问从而避免了非授权访问操作。
第七章:类的定义及其类对象的封装性 以前,定义结构体类型,描述一个对象 : struct SPerson //只有数据成员 { char name[20]; //姓名 char sex; //性别 int age; //年龄 }; 我们把一个对象可能具有的动作,加入到对象的描述中,就形成了类。
第七章:类的定义及其类对象的封装性 ◆ 7 . 1C++类的构成 • 1、class 声明: 〖举例〗 • 类似于struct,但是class中除变量的声明外,还含有函数的声明,还具有公有、保护、私有成员(数据或函数)。 • 2、成员类型(数据和函数) • (1)公有成员(public, 不可以省略) • (2)保护成员(protected, 不可以省略) • (3)私有成员(private, 放在第一段时,可以省略) • 3、类的构造(建立) • (1)class (保留字)声明; • (2)声明或定义各段内容(public, protected, • private),段内定义的函数为inline型; • (3)语法规则:“{};”;类的继承。
第七章:类的定义及其类对象的封装性 ◆ 7 . 1C++类的构成 class <类名> { [ [private:] //私有成员,缺省存取权限 <数据成员及成员函数 > ] [ public: //公有成员 <数据成员及成员函数 > ] [ protected: //保护成员 <数据成员及成员函数 > ] }; 私有成员:只允许类内成员函数存取它 公有成员:允许类内和类外函数存取它 保护成员:允许类内和其派生类函数存取它
第七章:类的定义及其类对象的封装性 ◆ 7 . 2 成员函数的定义 • 1、在类定义体中声明函数或变量,在别处(实现文件,如*.cpp等)定义函数; • 2、声明函数时,函数的参数可以只指出参数的类型(如SetPoint(POINT, int);) • 3、声明和定义函数时,函数的返回类型要一致; • 4、在类之外定义成员函数时,必须在函数名之前加类名(如,void CGeoPoint::SetPoint(POINT p, int n )); • 5、函数的缺省变量值在声明时给定,而在实现定义时不需给出(如,int SetType(int nType = 1); int CGeoPoint::SetType(int nType/* = 1*/); ) • 6、内置函数:提高效率 • (1)隐式定义(函数定义在类定义体内); • (2)显示定义(函数定义在类定义体外,用冠以关键 • 字inline在函数类型前面);
第七章:类的定义及其类对象的封装性 ◆ 7 . 3 类与对象 • 1、类与对象的关系 • 类:把具有同样性质和功能的东西所构成的集合称为类。在C++中,可以把具有相同内部存储结构和相同一组操作的对象看成属于同一类。 • 对象:在指定一个类后,往往把属于这个类的对象称为类的实例。实际上对象和实例表达的是同一个意思。 • 类与对象的关系:在C++中可以理解成数据类型和变量的之间的关系,如 double x; CObject obj; • 对象的定义(类的实例化): • (1)在定义类的同时创建对象:(全局对象,容易造成混乱,在生命期内有效)〖举例〗 • (2)在使用时定义对象
第七章:类的定义及其类对象的封装性 ◆ 7 . 3 类与对象 • 2、类的使用 • 类的使用:定义对象,通过类的公有函数或成员变量访问或作用于类。 • (1)类的对象:CGeoMap map • map.SetScale(1000); • //等价于map.CGeoMap::SetScale(1000); • map.m_nScale; • (2)类的指针: • CGeoMap* pMap = new CGeoMap; • //开辟空间(书中相关内容有误) • pMap->SetScale(1000); • pMap->m_nScale; • delete pMap; //释放空间
第七章:类的定义及其类对象的封装性 ◆ 7 . 3 类与对象 3、名字解析 map.SetScale(1000);等价于map.CGeoMap::SetScale(1000);所以,在多个类中可以定义相同的成员变量或成员函数而不会出现二义性。如: • CGeoPoint{ • public: • void Draw(CDC* pDC); • }; CGeoPoint point; CGeoLine line; point.Draw(pDC); line.Draw(pDC); //无二义 • CGeoLine{ • public: • void Draw(CDC* pDC); • };
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 目的:与一般数据类型一样使用,使得建立的对象始终与其定义域相关,并且对对象进行初始化或对象占有空间的释放。 构造函数和析构函数除具有普通函数的许多共性外,还具有一些独特的特性,如下: (1)无函数返回类型; (2)不能被继承; (3)构造函数可以有缺省参数; (4)析构函数可以是虚的(virtual),但构造函数不可以; (5)不可以取地址;(不可以利用函数指针) (6)不能用常规方法调用构造函数;当使用限定名(对象 名)时可以调用析构函数;如,A a; a.~A(); (7)当定义对象时,编译程序自动调用构造函数;当删除对 象时,编译程序自动地调用析构函数;
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 1、构造函数 (1) 构造函数的名字必须与类名相同,否则与一般成员函数一样; (2) 构造函数没有返回值; (3) 构造函数的目的是对对象进行初始化;(否则变量随机取值,易造成错误) (4) 构造函数是在对象被构造时被自动调用;(对象指针须在分配空间时自动调用构造函数),如,A* p; //还没有调用构造函数p = new A;// 调用构造函数 (5)构造函数可以调用自定义函数以初始化对象;
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 2、参数化的构造函数 对象的初始化通过构造函数传递的参量进行的,在构造对象必须给定参数。
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 3、缺省参数的构造函数 缺省参数:单缺省、多缺省(遵循原则:缺省参数必须是参数表中最后的参数(即最右端)) spliteFile(char* szFullName, char* szDir = NULL, char* szName = NULL, char* szTitle = NULL, char* szExt = NULL ); 缺省参数并不只用于构造函数,一般的成员函数,甚至于一般的全局函数都可以使用缺省函数。
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 4、多构造函数 构造函数的重载。 一个类可以具有多个构造函数,以适应不同的场合。 多构造函数情况下,当有缺省参数的构造函数时,注意避免发生二义性。
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 5、拷贝构造函数 是特殊的构造函数;将参数代表的对象逐域拷贝到新创建的对象中。 (1)系统产生:A a(10,20); A b(a); (2)用户定义: A(const A& p ){x=p.x;y=p.y;}
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 6、动态存储 C 中:malloc()与free(); C++中:new与delete; new 与malloc相比好处为: ①new自动计算所分配的类型的大小,既方便,有避免了分配空间的偶然错误; ②自动返回正确的指针类型,不需要指针的类型转换; ③可以用new将分配的对象初始化。
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 (1)new的使用 名字指针 = new 名字类型[初始化值];如, CGeoPoint* point = new CGeoPoint; Int * mm = new int[100]; memset(mm,0x00,sizeof(int)*100);//将空间清空 double* nn = new double[1][2][3];//数组中的任何一维大小不能缺省
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 (2)delete的使用 delete 名字指针;如, delete point; delete[ ] mm; delete[ ] nn; 备注:删除之前要判断当前指针是否已经为空
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 • (3)new和delete 的使用 • new和delete配对使用。如, • ①动态分配和释放存储区 (int* p = new int; delete p;) • ②动态分配并初始化存储区; • int* p = new int(200); //将200赋值给p • delete p; //要判断是否为空 • ③动态分配数组 〖举例〗 • int* p = new int[50]; • delete[ ] p;//要判断是否为空 • ④为结构类型的变量分配存储区 〖举例〗
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 • ⑤为对象动态分配存储区 • CGeoPoint* p = new CGeoPoint(10,20); • If( NULL != p ) • { • delete p; • p = NULL; • }
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 • ⑥为对象数组动态分配存储区 • CGeoPoint* p = new CGeoPoint[10]; • If(NULL != p) • { • delete[ ] p; • p = NULL; • } • 〖举例〗
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 7、析构函数 是类的成员函数,类名前家“~”,无参数和返回类型,用于空间的释放(如delete操作)。
第七章:类的定义及其类对象的封装性 ◆ 7 . 5 静态成员 1、定义 在类定义中,其成员(数据成员和函数成员)可以声明成静态的,即用关键字static,这些成员被称为静态成员。它的特征是不管这个类创建了多少个对象,而其静态成员只有一个副本(拷贝),这个副本对该类所有的对象共享。
第七章:类的定义及其类对象的封装性 ◆ 7 . 5 静态成员 2、静态数据成员 〖举例〗
第七章:类的定义及其类对象的封装性 ◆ 7 . 5 静态成员 • 3、静态成员函数 • (1)成员函数前加static关键字; • (2)使用时需指出作用(调用)对象,或用“类名::”作为限定词;如b2.Add(b1)或Office::Add(b1); • (3)不属于某个特定的对象,而是属于类的;不像一般的成员函数那样随意地访问对象中的非静态的数据内容。 • (4)函数内容(数据成员)受到一定的限制;函数中没有this指针,一般数据成员不可以使用,习惯是静态函数访问静态数据成员。 • (参见上面例子)
第七章:类的定义及其类对象的封装性 ◆ 7 . 6 类对象作为成员 1、类对象成员的定义与标准数据类型相同; 2、类(A)对象成员(b)的初始化,可以在类A构造的同时构造(初始化)b; 〖举例〗 方法一:b是对象,A::A( ) : b( XX )或 A::A( int zz ) : b(zz); 方法一:b是对象指针,除采用方法一外,可以利用对象指针pB开辟空间时构造;pB = new B(zz);
第七章:类的定义及其类对象的封装性 ◆ 7 . 7 对象数组 • 1、每个数组元素都是对象的数组是对象数组; • 2、对象对应的类必须有一个不带参数或带缺省参数的构造函数,因为在定义对数组时无法给构造函数传递参数; • A a[10]; • A* pA = new A[10]; • 3、区别于“数组对象”
第七章:类的定义及其类对象的封装性 ◆ 7 . 8 C++中的封装性 封装实际上就是信息隐蔽。 1、对象的封装 将对象的属性(数据内容)和作用于这些属性上的作(函数内容)封装在一起,对象的使用者只能通过提供它的接口(协议)使用这个对象。对象的内部是被保护起来的,他的使用是通过发送消息——即调用公有成员函数完成的。 2、程序的模块化 文件(程序)的组织形式 (1)类说明(声明)文件(*.h) (2)类实现(定义)文件(*.cpp) (3)常量或宏定义文件(*.h) (4)类的使用文件(*.cpp)
第七章:类的定义及其类对象的封装性 ◆ 7 . 9 实例分析 CGeoProject CGeoMap CGeoEdit CGeoPrjSet CGeoIO CGeoLayer CGeoPoint CGeoLine CGeoSurface CGeoRegion CGeoRoute CGeoGroup
第七章:类的定义及其类对象的封装性 ◆ 总结: • 类的组成及定义 • 构造函数和析构函数的使用 • 动态分配机制 • 静态成员变量和静态成员函数 • 类对象成员的构造
第七章:类的定义及其类对象的封装性 • struct GeoPoint • { • double x; • double y; • double z; • }; ◆ 7 . 1C++类的构成 • class GeoPoint • { • private: //可以省略 • double x; • double y; • double z; • public: • void SetValue(double x ,double y,double z); • void GetValue(double& x ,double& y, double& z); • protected: • void ChangePoint(); • }; 返回
第七章:类的定义及其类对象的封装性 • struct GeoObject • { • char* name; • int nPointNum; • POINT* pPoints; • }; ◆ 7 . 4 构造函数与析构函数 GeoObject* pObj = new GeoObject; pObj->name = new char[80]; pObj-> nPointNum = 100; pObj-> pPoints = new POINT[100]; 返回
第七章:类的定义及其类对象的封装性 • if( NULL != m_ulIdx ) • { • for(int m=0;m<1024;m++) • { • delete[ ] m_ulIdx[m]; • m_ulIdx[m] = NULL; • } • delete[ ] m_ulIdx; • m_ulIdx=NULL; • } ◆ 7 . 4 构造函数与析构函数 • if( NULL == m_ulIdx ) • { • ...... • m_ulIdx = new unsigned long*[1024]; • for(int m=0; m<1024; m++) • { • ...... • unsigned long midnum=0; • fread(&midnum,sizeof(unsigned long),1,indexfp); • m_ulIdx[m]=new unsigned long[midnum+1]; • memset(m_ulIdx[m],0x00,sizeof(unsigned long)*(midnum+1)); • m_ulIdx[m][0]=midnum; • fread(&m_ulIdx[m][1],sizeof(unsigned long),midnum,indexfp); • ...... • } • } 返回
第七章:类的定义及其类对象的封装性 ◆ 7 . 4 构造函数与析构函数 • if(NULL != m_pGeoLayer) • { • for(int ii=0;ii<m_strarrayLandFile.GetSize();ii++) • { • delete m_pGeoLayer[ii]; • m_pGeoLayer[ii] = NULL; • } • delete [] m_pGeoLayer; • m_pGeoLayer = NULL; • } • CGeoLayer ** m_pGeoLayer = NULL; • m_pGeoLayer = new CGeoLayer*[m_strarrayLandFile.GetSize()]; • for(int ii=0;ii<m_strarrayLandFile.GetSize();ii++) • { • m_pGeoLayer[ii] = new CGeoLayer(m_strarrayLandFile.GetAt(ii)); • m_pGeoLayer[ii]->SetGeoMap(this); • } 返回
第七章:类的定义及其类对象的封装性 • void Office::Add() • { • person_count += nPerson; • //有问题,没有this指针,使用nPerson错误。 • } • void Office::Add(office p) • { • person_count += p .nPerson; • //正确,通过传递成员变量 • } • Office b1; //1.1 • Office b2; //1.2 • Office b3; //1.3 • Office b4; //1.4 ◆ 7 . 5 静态成员 • class Office • { • static int person_count; • int nPerson; • public: • Office(); • ~ Office(){}; • static void Add(); • }; • int Office:: person_count = 0; • Office:: Office () • { • nPerson = 2; • person_count += 1; • } 返回
第七章:类的定义及其类对象的封装性 ◆ 7 . 6 类对象作为成员 • Class B • { • int z; • B(); • ~B(); • }; • Class A • { • B b; • B* pB; • int x; • int y; • A(); • A(int zz); • }; • A::A():b(10) • { • } • A::A(int zz):b(zz) • { • } • A::A(int zz) • { • pB = new B(zz); • } 返回