《第2章面向对象程序设计精.ppt》由会员分享,可在线阅读,更多相关《第2章面向对象程序设计精.ppt(29页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第2章面向章面向对象程序象程序设计第1页,本讲稿共29页2.1 2.1 类和对象类和对象类和对象是面向对象编程的核心,类和对象类似建筑图类和对象是面向对象编程的核心,类和对象类似建筑图纸和大楼的关系,类是对象的一种抽象,对象是类的一个实纸和大楼的关系,类是对象的一种抽象,对象是类的一个实例。在面向对象世界中,一切事物都可以用对象表示,对象例。在面向对象世界中,一切事物都可以用对象表示,对象间通过消息进行交流,无需了解对象的内部实现,只要知道间通过消息进行交流,无需了解对象的内部实现,只要知道各个对象提供的功能接口就能实现各种高级功能。各个对象提供的功能接口就能实现各种高级功能。第2页,本讲稿
2、共29页2.1.1 2.1.1 类和对象的关系类和对象的关系类是一种自定义数据类型,类似于类是一种自定义数据类型,类似于C中的结构体中的结构体(struct),不同之处在于类中包括数据和函数,而结构体),不同之处在于类中包括数据和函数,而结构体只有数据。类是对象的形式上的抽象,不是一个实际存在的只有数据。类是对象的形式上的抽象,不是一个实际存在的事物,它规定有哪些数据成员,哪些成员函数及具体功能,事物,它规定有哪些数据成员,哪些成员函数及具体功能,是对具体事物的一种描述。对象是类的实现(是对具体事物的一种描述。对象是类的实现(implement),),对象根据类的描述信息生成一个真实的事物,占
3、用实际内存,对象根据类的描述信息生成一个真实的事物,占用实际内存,对象生成时要调用类的构造函数(对象生成时要调用类的构造函数(construct)进行初始化)进行初始化(initialize),对象释放(),对象释放(Release)时要调用类的析构函)时要调用类的析构函数做必要的清理工作。数做必要的清理工作。第3页,本讲稿共29页2.1.2 2.1.2 定义类定义类使用使用class关键字定义一个类,可在类中添加成员变量关键字定义一个类,可在类中添加成员变量(member variable)和函数。一般在类里声明函数,在类)和函数。一般在类里声明函数,在类外实现函数以体现类的封装性,也可以声
4、明和实现都在类中外实现函数以体现类的封装性,也可以声明和实现都在类中完成,适用于简短且频繁调用的成员函数。通过类名调用函完成,适用于简短且频繁调用的成员函数。通过类名调用函数使用作用域解析操作符数使用作用域解析操作符:,如,如A:Calc();,通过对象名调,通过对象名调用函数使用圆点操作符用函数使用圆点操作符.,如,如a.Calc();。第4页,本讲稿共29页2.1.3 2.1.3 构造函数构造函数类不同于类不同于C+的基本数据类型,类的结构可能非常复杂,的基本数据类型,类的结构可能非常复杂,包括大量的成员变量和函数,仅仅简单的分配一块足够大小包括大量的成员变量和函数,仅仅简单的分配一块足够
5、大小的内存给类对象是不够的,还需要对类中的成员变量进行集的内存给类对象是不够的,还需要对类中的成员变量进行集中初始化。中初始化。C+提供构造函数来完成类对象的初始化操作,提供构造函数来完成类对象的初始化操作,构造函数先根据类的大小分配一块足够的内存用于存放类对构造函数先根据类的大小分配一块足够的内存用于存放类对象,再根据构造函数传入的参数和具体实现完成类对象的初象,再根据构造函数传入的参数和具体实现完成类对象的初始化。始化。第5页,本讲稿共29页2.1.4 2.1.4 析构函数析构函数类在释放自身之前可能需要做一些清理工作,如类在使类在释放自身之前可能需要做一些清理工作,如类在使用过程中动态分
6、配了内存空间,在类释放之前需要手动释放用过程中动态分配了内存空间,在类释放之前需要手动释放这些内存。析构函数用于完成类释放之前的一些清理工作,这些内存。析构函数用于完成类释放之前的一些清理工作,由由C+自动调用。自动调用。同构造函数,析构函数名为在类名前加同构造函数,析构函数名为在类名前加符号,如符号,如Rect(),析构函数没有返回值也没有参数列表,每个类只有一个,析构函数没有返回值也没有参数列表,每个类只有一个析构函数,若没有添加析构函数,析构函数,若没有添加析构函数,C+提供默认的析构函数,提供默认的析构函数,但什么也不做。但什么也不做。第6页,本讲稿共29页2.1.5 2.1.5 内联
7、函数内联函数程序代码中经常要调用函数,从调用点进入到函数的内程序代码中经常要调用函数,从调用点进入到函数的内部,执行完毕后返回调用点,函数调用需要一定的开销。部,执行完毕后返回调用点,函数调用需要一定的开销。C语言为节省函数调用带来的开销,常使用宏(语言为节省函数调用带来的开销,常使用宏(macro)的方)的方式模拟函数,如求和运算定义宏式模拟函数,如求和运算定义宏#define SUM(a,b)(a+b),编译时用宏替换代码,减少函数调用的开销。,编译时用宏替换代码,减少函数调用的开销。第7页,本讲稿共29页2.1.6 static2.1.6 static成员成员static(静态)关键字在
8、不同场合具有不同的意义,也(静态)关键字在不同场合具有不同的意义,也是常混淆用途的一个关键字(是常混淆用途的一个关键字(keyword)。在)。在C语言中,语言中,static有两层含义,若在函数外用有两层含义,若在函数外用static修饰全局变量和函数,修饰全局变量和函数,表示具有文件作用域,只能在本文件中可用,不能在其他文表示具有文件作用域,只能在本文件中可用,不能在其他文件中使用。件中使用。第8页,本讲稿共29页2.1.7 const2.1.7 const成员成员const(constant常量)修饰符用于表示一个变量在初常量)修饰符用于表示一个变量在初始化后不能再被修改,即只读(始化后
9、不能再被修改,即只读(read only)。)。const变量在变量在定义时必须同时进行初始化,常用在函数参数中,表示该参定义时必须同时进行初始化,常用在函数参数中,表示该参数在函数内部不会被修改。数在函数内部不会被修改。在传递类对象时,若采用传值方式,将类对象的拷贝传在传递类对象时,若采用传值方式,将类对象的拷贝传入函数,在类对象复杂的时候效率很低,一般传递类对象的入函数,在类对象复杂的时候效率很低,一般传递类对象的引用,但若使用引用方式,类对象的值可能会被函数修改,引用,但若使用引用方式,类对象的值可能会被函数修改,这时使用这时使用const修饰符可限定类对象的值为只读,如修饰符可限定类对
10、象的值为只读,如GetLength(const CString&str)。第9页,本讲稿共29页2.1.8 2.1.8 友元友元类的私有成员一般情况下在类外不可访问,但有时候需类的私有成员一般情况下在类外不可访问,但有时候需要在类外访问,可使用要在类外访问,可使用friend关键字,在被访问类中声明为关键字,在被访问类中声明为friend的类或函数可以访问其私有成员。的类或函数可以访问其私有成员。使用使用friend修饰的类、函数称为友元类、友元函数,友修饰的类、函数称为友元类、友元函数,友元不是类的成员,但能像类成员函数一样访问类的私有成员,元不是类的成员,但能像类成员函数一样访问类的私有成
11、员,当需要同时访问多个类的私有成员,适宜使用友元。当需要同时访问多个类的私有成员,适宜使用友元。第10页,本讲稿共29页2.2 2.2 运算符重载运算符重载C+提供一些运算符用于完成基本的运算,如提供一些运算符用于完成基本的运算,如+可以计可以计算两个整型或浮点类型数值的和,算两个整型或浮点类型数值的和,=可以判断两个值是否相可以判断两个值是否相等,但都只能用于预置的基本类型。若想用等,但都只能用于预置的基本类型。若想用+得到两个字符得到两个字符串拼接后的新字符串,用串拼接后的新字符串,用=判断两个类是否包含相同的值,判断两个类是否包含相同的值,可使用可使用C+提供的运算符重载功能,类似函数重
12、载,运算符提供的运算符重载功能,类似函数重载,运算符可看做函数名,运算符两边的变量可看做函数的参数,调用可看做函数名,运算符两边的变量可看做函数的参数,调用时根据运算符的参数数目和类型自动选择匹配的版本。时根据运算符的参数数目和类型自动选择匹配的版本。第11页,本讲稿共29页2.2.1 2.2.1 了解运算符重载了解运算符重载运算符重载在定义时使用运算符重载在定义时使用operator关键字,根据运算关键字,根据运算符操作数的数目分为一元重载和二元重载,如符操作数的数目分为一元重载和二元重载,如+、/、%为二为二元运算符,元运算符,+、-为一元运算符,为一元运算符,-当做减号为二元,当做负当做
13、减号为二元,当做负号为一元。号为一元。运算符可看做为函数,如运算符可看做为函数,如operator+类似类似Add(STR a,int b);+两边的操作数类似参数两边的操作数类似参数a、b,重载的运算符可作,重载的运算符可作为类的成员,也可作为类的友元函数,也可作为普通函数。为类的成员,也可作为类的友元函数,也可作为普通函数。第12页,本讲稿共29页2.2.2 2.2.2 一元重载一元重载一元重载只有一个操作数即类名,一般作为类成员,常一元重载只有一个操作数即类名,一般作为类成员,常用的一元运算符有自增、自减、求负运算符,其中自增、自用的一元运算符有自增、自减、求负运算符,其中自增、自减运算
14、有前后之分,运算符在前表示先自增自减,然后再赋减运算有前后之分,运算符在前表示先自增自减,然后再赋值,在后表示先赋值然后再自增自减,若为单独的表达式则值,在后表示先赋值然后再自增自减,若为单独的表达式则没有区别。默认重载没有区别。默认重载+、-为前缀版本,若表示后缀版本,为前缀版本,若表示后缀版本,添加一个添加一个int参数。参数。第13页,本讲稿共29页2.2.3 2.2.3 二元重载二元重载二元重载有两个操作数,若作为类成员,只需一个参数,二元重载有两个操作数,若作为类成员,只需一个参数,否则需要两个参数。参数的顺序代表操作数的位置,如否则需要两个参数。参数的顺序代表操作数的位置,如ope
15、rator+(A a,int b)调用形式为调用形式为a+2;不能为不能为2+a;若调换若调换位置也可用,要再重载一次如位置也可用,要再重载一次如operator+(int b,A a)第14页,本讲稿共29页2.3 2.3 继承性继承性面向对象编程的一个重要特性是继承性,类之间可以有面向对象编程的一个重要特性是继承性,类之间可以有继承关系,通过从一个父类派生出子类,子类在拥有父类功继承关系,通过从一个父类派生出子类,子类在拥有父类功能的基础上,添加新增的功能,无需从零开始构建整个类,能的基础上,添加新增的功能,无需从零开始构建整个类,只需要补充新增的功能即可。只需要补充新增的功能即可。C+允
16、许多重继承,即从多个允许多重继承,即从多个父类派生出一个子类,子类拥有多个父类的功能,多重继承父类派生出一个子类,子类拥有多个父类的功能,多重继承虽功能强大,却复杂难以理解,在虽功能强大,却复杂难以理解,在C#、Java中已取消了多中已取消了多重继承,应避免使用。重继承,应避免使用。MFC类库中绝大多数类都继承于类库中绝大多数类都继承于CObject类,类,CObject类提供了基本的服务,如运行时(类提供了基本的服务,如运行时(runtime)的类型判断、)的类型判断、对象的序列化存储等,所有从对象的序列化存储等,所有从CObject类继承的类自动具有类继承的类自动具有这些功能。这些功能。第
17、15页,本讲稿共29页2.3.1 2.3.1 类的继承类的继承父类称为基类,从基类继承的子类称为派生类,在类定父类称为基类,从基类继承的子类称为派生类,在类定义时指定要继承的基类,派生类自动获取基类的成员变量和义时指定要继承的基类,派生类自动获取基类的成员变量和函数,但不会获取基类的构造函数和析构函数。函数,但不会获取基类的构造函数和析构函数。创建派生类对象时,首先要初始化基类,可在派生类的创建派生类对象时,首先要初始化基类,可在派生类的构造函数里调用基类的构造函数,若没有显示调用基类的构构造函数里调用基类的构造函数,若没有显示调用基类的构造函数,自动调用基类的默认无参数版本构造函数。造函数,
18、自动调用基类的默认无参数版本构造函数。第16页,本讲稿共29页2.3.2 2.3.2 访问控制访问控制类继承有三种方式:公有(类继承有三种方式:公有(public)、保护)、保护(protected)、私有()、私有(private)继承。基类的私有成员无)继承。基类的私有成员无论何种继承方式,在派生类中都不可访问。论何种继承方式,在派生类中都不可访问。若为私有继承,基类的公有和保护成员在派生类中变为若为私有继承,基类的公有和保护成员在派生类中变为私有。若为保护继承,基类的公有和保护成员在派生类变为私有。若为保护继承,基类的公有和保护成员在派生类变为保护成员。若为公有继承,基类的公有成员和保护
19、成员在派保护成员。若为公有继承,基类的公有成员和保护成员在派生类中保持不变,一般情况下只使用生类中保持不变,一般情况下只使用public公有继承方式。公有继承方式。第17页,本讲稿共29页2.3.3 2.3.3 调用流程调用流程基类的构造函数和析构函数不会被派生类继承。若类基类的构造函数和析构函数不会被派生类继承。若类B继承类继承类A,类,类C继承类继承类B,则创建一个类,则创建一个类C对象时,先调用类对象时,先调用类A的构造函数,然后类的构造函数,然后类B,再调用类,再调用类C的构造函数,若类的构造函数,若类C对对象释放时,先调用类象释放时,先调用类C的析构函数,然后类的析构函数,然后类B,
20、最后调用类,最后调用类A的析构函数。即构造函数调用顺序为从基类到派生类,析构的析构函数。即构造函数调用顺序为从基类到派生类,析构函数与构造函数顺序相反,从派生类到基类。函数与构造函数顺序相反,从派生类到基类。第18页,本讲稿共29页2.4 2.4 多态性多态性用类指针去调用类成员函数时,根据指针的类型即可确用类指针去调用类成员函数时,根据指针的类型即可确定调用的函数版本。如类定调用的函数版本。如类B继承类继承类A,类,类B重定义了类重定义了类A的的Calc函数,若有类函数,若有类A指针指针p调用调用Calc函数,调用了类函数,调用了类A版本版本的的Calc函数,若将类函数,若将类A指针指针p改
21、为指向类改为指向类B对象(指针类型没对象(指针类型没有变),再调用有变),再调用Calc函数,仍调用类函数,仍调用类A版本的版本的Calc函数。重函数。重定义函数的调用仅与指针类型相关,与指针实际指向对象无定义函数的调用仅与指针类型相关,与指针实际指向对象无关。关。第19页,本讲稿共29页2.4.1 2.4.1 多态性的实现多态性的实现多态性与函数重定义的区别在于:重定义函数的调用与多态性与函数重定义的区别在于:重定义函数的调用与指针类型相关,在程序编译时就确定了调用的函数版本,多指针类型相关,在程序编译时就确定了调用的函数版本,多态性的函数调用与指针实际所指对象相关,在程序运行时才态性的函数
22、调用与指针实际所指对象相关,在程序运行时才确定调用的函数版本。确定调用的函数版本。多态性通过一种晚期绑定的方式实现运行时的识别,实多态性通过一种晚期绑定的方式实现运行时的识别,实现晚期绑定可使用现晚期绑定可使用virtual关键字声明一个函数是虚函数,只关键字声明一个函数是虚函数,只需要在基类中声明函数为虚函数,在派生类中对该函数重写需要在基类中声明函数为虚函数,在派生类中对该函数重写后,就可实现动态绑定。后,就可实现动态绑定。第20页,本讲稿共29页2.4.2 virtual2.4.2 virtual虚函数虚函数添加一个添加一个virtual关键字就可以实现动态绑定,在于编译关键字就可以实现
23、动态绑定,在于编译器为每个包含虚函数的类生成一个虚函数表(器为每个包含虚函数的类生成一个虚函数表(virtual table),同时在类对象的内存空间的头部添加一个虚指针,),同时在类对象的内存空间的头部添加一个虚指针,指向生成的虚函数表。虚函数表存放该类所有的虚函数,若指向生成的虚函数表。虚函数表存放该类所有的虚函数,若在派生类中重写了基类的虚函数,则派生类的虚函数表中存在派生类中重写了基类的虚函数,则派生类的虚函数表中存放的是重写后的虚函数。放的是重写后的虚函数。第21页,本讲稿共29页2.4.3 2.4.3 抽象类抽象类在实际开发中,可能某些基类只是做个规范,形式上确在实际开发中,可能某
24、些基类只是做个规范,形式上确定有哪些基本成员及其功能,并不涉及具体的实现。如基类定有哪些基本成员及其功能,并不涉及具体的实现。如基类CMap定义有虚函数定义有虚函数Draw(),作为所有图形类的绘制函数,作为所有图形类的绘制函数,基类下有派生类基类下有派生类CLine、CPoint、CRect分别用于绘制线、分别用于绘制线、点、矩形,具体的图形绘制方法在派生类的点、矩形,具体的图形绘制方法在派生类的Draw函数里完函数里完成,而基类的成,而基类的Draw只是一个接口的规范,不需要具体实现,只是一个接口的规范,不需要具体实现,此时可设置此时可设置Draw函数为纯虚函数。函数为纯虚函数。第22页,
25、本讲稿共29页2.5 2.5 模板模板标准标准C+库除了包含标准库除了包含标准C函数库、函数库、IO输入输出类、输入输出类、string字符串类之外,还提供一套强大的通用类和算法库,字符串类之外,还提供一套强大的通用类和算法库,即标准模板库即标准模板库STL(Standard Template Library),包括),包括常见的数据结构和算法,如链表、栈、队列等。常见的数据结构和算法,如链表、栈、队列等。得益于得益于C+的模板(的模板(Template)机制,)机制,STL适用于任适用于任何数据类型,如链表何数据类型,如链表list既可存放整型,也可存放既可存放整型,也可存放string类型
26、。类型。模板也被称为泛型编程,忽略实际的数据类型,使用模板的模板也被称为泛型编程,忽略实际的数据类型,使用模板的函数和类可以适用于多种数据类型,从而节省工作量,提高函数和类可以适用于多种数据类型,从而节省工作量,提高代码重用性。代码重用性。第23页,本讲稿共29页2.5.1 2.5.1 如何定义模板如何定义模板在定义类或函数时使用模板可以忽略实际数据类型,调在定义类或函数时使用模板可以忽略实际数据类型,调用时根据实际的数据类型,生成一个函数或类的具体定义。用时根据实际的数据类型,生成一个函数或类的具体定义。通过在函数或类的定义前添加通过在函数或类的定义前添加template,表明定,表明定义的
27、函数或类使用了模板机制,义的函数或类使用了模板机制,class是类型关键字,是类型关键字,T是一是一个未知的数据类型,调用时被实际类型替换。若有两个模板个未知的数据类型,调用时被实际类型替换。若有两个模板参数,形式为参数,形式为template,T1和和T2为两为两个未知的数据类型。个未知的数据类型。第24页,本讲稿共29页2.5.2 2.5.2 模板类模板类模板类是泛型程序设计的基础,可以处理多种类型的数模板类是泛型程序设计的基础,可以处理多种类型的数据,将通用功能集成到模板类中,可节省大量重复性工作。据,将通用功能集成到模板类中,可节省大量重复性工作。类似于函数模板,定义模板类之前使用类似
28、于函数模板,定义模板类之前使用template做模板声明,在类中可用未知类型做模板声明,在类中可用未知类型T进行相关处理。进行相关处理。template只能在其后的类或函数中使用一次,只能在其后的类或函数中使用一次,若要在多个类或函数中使用模板,需要各自在定义前声明一若要在多个类或函数中使用模板,需要各自在定义前声明一次。传入实际数据类型时,形式为次。传入实际数据类型时,形式为Calc c1(12,35);在在中输入数据类型。中输入数据类型。第25页,本讲稿共29页2.5.3 2.5.3 标准模板库标准模板库STLSTLSTL是标准是标准C+库的一部分,包含链表(库的一部分,包含链表(list
29、)、向量)、向量(vector)、栈()、栈(stack)、队列()、队列(queue)等常见数据结)等常见数据结构,构,STL中的类都是模板类,适用于任意数据类型,也称为中的类都是模板类,适用于任意数据类型,也称为容器类。容器类。STL使用迭代器(使用迭代器(iterator)遍历容器中的元素,)遍历容器中的元素,迭代器类似于指针,根据迭代器变量可查找到容器中的某个迭代器类似于指针,根据迭代器变量可查找到容器中的某个元素。元素。通过迭代器重载的运算符可操作迭代器,如通过迭代器重载的运算符可操作迭代器,如+用于将用于将迭代器指向下一个元素,迭代器指向下一个元素,-用于指向上一个元素,用于指向上
30、一个元素,=和和!=用用于判断两个迭代器是否指向同一个元素,于判断两个迭代器是否指向同一个元素,*用于获取迭代器用于获取迭代器指向元素的引用。指向元素的引用。第26页,本讲稿共29页2.6 2.6 异常处理异常处理程序在执行过程中时常会发生一些异常(程序在执行过程中时常会发生一些异常(exception),),如打开文件时找不到指定文件、分配内存时内存不足、除法如打开文件时找不到指定文件、分配内存时内存不足、除法运算中分母为运算中分母为0、连接不上数据库等,有些异常可通过代码、连接不上数据库等,有些异常可通过代码判断,但有些是难以预测的。为保证程序运行时能够正确处判断,但有些是难以预测的。为保
31、证程序运行时能够正确处理各种异常情况,不会直接崩溃退出,理各种异常情况,不会直接崩溃退出,C+提供异常处理机提供异常处理机制,可以获取运行时的异常情况,并提供错误处理方法,从制,可以获取运行时的异常情况,并提供错误处理方法,从而提高程序的健壮性。而提高程序的健壮性。第27页,本讲稿共29页2.6.1 2.6.1 处理程序异常处理程序异常C+提供提供try和和catch关键字处理异常情况,将正常执行关键字处理异常情况,将正常执行的代码放入的代码放入try语句块中,语句块中,catch块中放入处理异常的代块中放入处理异常的代码。若无异常发生,只执行码。若无异常发生,只执行try块中的语句,若发生了
32、异常,块中的语句,若发生了异常,停止执行停止执行try块中剩下的语句,直接跳入块中剩下的语句,直接跳入catch块中执行异常块中执行异常处理代码,使用处理代码,使用try和和catch可以将正常代码和异常代码区分可以将正常代码和异常代码区分开来,增强代码的可读性。开来,增强代码的可读性。第28页,本讲稿共29页2.6.2 2.6.2 自定义异常类自定义异常类throw可抛出任意类型的异常,可自定义一个异常类,可抛出任意类型的异常,可自定义一个异常类,用以提示更多的错误信息。用以提示更多的错误信息。MFC类库提供一系列异常类,用类库提供一系列异常类,用以抛出不同类型的异常,如内存不足抛出以抛出不同类型的异常,如内存不足抛出CMemoryException异常、文件错误抛出异常、文件错误抛出CFileException异常。异常。第29页,本讲稿共29页