版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第十一章 多态性和虚函数(2)应用与讨论面向对象程序设计(C+)11.8 构造抽象接口多态性的优点之一11.8.1 问题描述 传达员:下午在会议室开会!项目规划公司发展策略11.8.2 静态绑定下的实现 传达员只负责通知某时某地开会,至于开什么会,怎么开,他才不管呢。 然而实现时,程序员必须分清楚通知的对象是谁?然后决定应该调用那一个对象的“开会函数”。switch(emp_type) case “CTO”: (CTO_manager *)emp)- meeting(); break; case “Chair”: (Chair_manager *)emp)-meeting(); break;
2、default: ERROR();11.8.3 动态绑定下的实现项目规划公司发展策略传达员:下午在会议室开会!11.8.3 动态绑定下的实现(续)CTO cto;Manager * pman ;pman = &cto; / 把所有的派生类对象当成基类处理pman - meeting() ; / 通过抽象接口实现 11.9 提高模块的独立性多态性的优点之二:可扩展性好11.9.1 静态绑定下的扩充讨论: 当需求发生变化时, 如何修改代码? 设置line的type时必须问一下:“嘿, 我可以设成L么? 修改enum shape_type = P,C,Y,L; 定义Line类; 修改函数 draw_
3、all(),由于switch逻辑的存在,因此代码的修改量是呈组合数量级增长的。因此,可扩展性很不好!11.9.2 动态绑定下的扩充 现在要增加类Line,只需要:从基类Shape中派生出Line类;无需设置类型域,无需改变其它任何的代码!class Line : public Shape public: Line( Point s,Point e ):start(s),end(e); void setLine( int, int, int , int ); int getX1() const return x1; int getY1() const return y1; int getX2()
4、 const return x2; int getY2() const return y2; virtual void printShapeName() const cout “Line: ; virtual void draw();protected: Point start, end; ;增加line类修改main()函数 (没有任何变化)int main() Point point1( 7, 11 ); / create a Point Circle circle1( 3.5, 22, 8 ); / create a Circle Cylinder cylinder1( 10, 3.3,
5、 10, 10 ); / create a Cylinder Circle circle2(2.5,10,15); /create a Circle Shape *arrayOfShapes 5 ; / array of base-class pointers arrayOfShapes 0 = &point1; arrayOfShapes 1 = &circle1; arrayOfShapes 2 = &cylinder1; arrayOfShapes 3 = &cycle2; for(int i=0; idraw(); / 动态关联 也就是说,假如只是增加类 Line,而没有创建该类的对象
6、,程序不需要做任何其它修改!增加Line对象后的main()函数(有细微的变化)int main() Point point1( 7, 11 ); / create a Point Circle circle1( 3.5, 22, 8 ); / create a Circle Cylinder cylinder1( 10, 3.3, 10, 10 ); / create a Cylinder Circle circle2(2.5,10,15); /create a Circle Line line(7,10,20,25); Shape *arrayOfShapes 5 ; / array of
7、 base-class pointers arrayOfShapes 0 = &point1; arrayOfShapes 1 = &circle1; arrayOfShapes 2 = &cylinder1; arrayOfShapes 3 = &cycle2; arrayOfShaoes 4 = &line; for(int i=0; idraw(); / 动态关联 即使需要创建类Line的对象,这种更改也是很容易实现的!习题 (30分钟内完成)信息学院教学办随机抽取100名学院的学生到中国科学院实习,他们来自不同的系:CS、Auto、和EE;但教学办并不知道他们应该到那个所实习。事实上,
8、计算机系的学生知道自己应该到软件所实习,自动化系到自动化所,电子工程系到电子所。假设每个学生在实习时首先要进行自我介绍。请编程模拟上述过程。 具体要求为:1. 设计学生类,信息包含姓名(8字节字符)、学号(8字节字符)、自我介绍(动态申请内存空间);学生的学号在对象生成时由程序统一设定,要求学号不重复; 2. 可以以下列方式产生学生对象: Cstudent stu1(“Mike”); / 仅设定姓名; Cstudent stu2(“Rick”, “I am rick , from USTC” ); / 仅设定姓名和自我介绍。 Cstudent stu3(stu2); / 从一个对象初始化另一个
9、对象,表示的是两个学生同 / 名,自我介绍内容也相同。3. 允许两个学生对象之间的赋值操作。如:stu1=stu2; 仅表示用stu2的自我介绍 内容设置stu1的自我介绍;4. 成员函数setmessage(char * )设置自我介绍内容; getmessage()获取自我介 绍内容;pratice()表示实习过程。11.10 防止组合爆炸 当存在多个类型相互组合的情况时,静态绑定下的switch逻辑将会出现“组合爆炸”。 而动态绑定下的代码扩充量则是“线性的”。11.10.1 引言:表达式求值+-5*124-5 + 12 * 4 可用表达式树来表示: 则表达式的值可按二叉树的后序遍历进行
10、计算,即先计算左子树的值和右子树的值,然后再计算结点的值。类的层次图结点类整形常量类负号运算符类双目运算符类加运算符类乘运算符类11.10.2 讨论:静态绑定的表达式求值求某个结点的值时,由于向上类型转换,结点的类型都变成Node *,因此,必须依赖switch逻辑判断左子树和右子树结点的类型,才能正确地绑定到左右子结点的求值函数,最后得到根结点的值。 class Plus: public Binop / 加运算符类public: Plus(Node *l, Node * r) :Binop(l,r) int eval() switch ( left-type) case P : switch
11、(right - type) case P: return(Plus*)left-eval()+(Plus*)right-eval(); break; case M: return(Plus*)left-eval()+(Minus*)right-eval(); break; ; ; case M : ; case U : ; ;共需要判断 n*n中情况11.10.3 动态绑定的表达式求值 动态绑定能消除switch逻辑,因此,求任意类型的结点N的值,可通过:1.向上类型转换:Node * np = N;2.动态绑定: np -eval() = (np-left)-eval() * (np-ri
12、ght)-eval();注:为简单起见,架设表达式中仅可能出现-(负号)、+(加运算)、*(乘运算)三种运算符、以及整形常量运算数。1. 设计结点的类层次结点类整形常量类负号运算符类双目运算符类加运算符类乘运算符类2. 实现各个结点类及主函数class Node / 基类,结点类 public: Node(); virtual Node() ; virtual int eval() error(); return 0; / 计算结点的值 ;派生类定义:class Binop:public Node /双目运算符public: Node * left, * right ; Binop() del
13、ete left; delete right ; Binop(Node *l, Node *r) left =l; /左结点 right = r; /右结点 ;class Plus: public Binop / 加运算符类public: Plus(Node *l, Node * r) :Binop(l,r) int eval() return left- eval() + right - eval() ; ;派生类定义(续):class Times:public Binop / 乘运算符类public: Times(Node *l, Node *r ) : Binop (l,r) int e
14、val() return left- eval() * right - eval() ; ;class Uminus:public Node / 负号运算符类 Node * operand ;public: Uminus(Node * op) operand = op ; Uminus() delete operand ; int eval() return operand - eval() ; ;主函数定义(续):class Int : public Node int value; public: int(int v) value = v; int eval() return value;
15、;int main() Node * np = new Plus ( new Uminus(new Int(5) , new Times (new int(12) ,new Int(4) );int result = np - eval () ;delete np; cout eval() - right - eval() ; ;class Divide:public Binop / 除运算符类public: Divide(Node *l, Node *r ) : Binop (l,r) int eval() return left- eval() / right - eval() ; 1。模
16、块独立性强; 2。代码的增加是线性的。11.10.4 讨论:交互式表达式计算需要编译器的lex和yacc支持:根据用户输入的表达式动态产生表达式树。具体实现(略):参见编译原理词法分析和语法分析相关章节。11.10.5 讨论:如何支持混合运算假设结点中可能有复数,并且允许复数和整数的混合运算,该如何处理? 例如:np1+np2有四种可能: 1):复数 + 复数 2):整数 + 复数 3):复数 + 整数 4):整数 + 整数 11.11 虚运算符重载函数注 多重指派技术:虚函数与运算符重载函数的完美结合!注:参见15.12节11.11.1 问题:混合运算矩阵、向量和标量混合*(乘)运算: M1
17、 * M2 ; 其中M1和M2是两个基类指针思路一:虚函数分析:虚函数的本质是能够动态确定一个对象的类型,而由于 m1*m2m1.operator*(m2)中存在两个未确定的类型。因此,试图依赖一次虚函数调用无法同时动态确定m1和m2的类型; 思路二:重载“+”分析:由于重载函数是必须依赖参数来决定确定具体调用的版本。而 m1*m2( m1.operator*(m2)中,m1可以通过虚函数动态绑定,但m2的类型尚未确定。因此单纯依赖重载函数不能解决。思路三:两者结合(多重指派技术)(不妨设为 Matrix * Vector)2. 定义重载函数: virtual multiply(Matrix
18、*) 计算M*V ; virtual multiply(Vector *) 计算V*V ; virtual multiply(Scalar *) 计算S*V;1. 定义virtual operator *; 通过调用m1.operator*(m2)动态绑定m1到Matrix*。3. 在m1.operator*(m2)中调用m2.multiply(m1) m2.multiply(Matrix *);该函数将动态绑定到Vector的mutiply(Matrix *);11.11.2 多重指派:程序的实现(demo)class Matrix; / 矩阵类class Scalar; / 标量类clas
19、s Vector; / 矢量类class Math / 基类 Mathpublic: / 一次指派,确定m1的类型 virtual Math& operator*(Math& rv) = 0; / 二次指派,确定m2的类型 virtual Math& multiply(Matrix*) = 0; virtual Math& multiply(Scalar*) = 0; virtual Math& multiply(Vector*) = 0; virtual Math() ;class Matrix : public Math public: / 一次指派 Math& operator*(Mat
20、h& rv) return rv.multiply(this); / 二次指派 Math& multiply(Matrix*) cout “Matrix * Matrix” endl; return *this; Math& multiply(Scalar*) cout Scalar * Matrix endl; return *this; Math& multiply(Vector*) cout Vector * Matrix endl; return *this; ;class Scalar : public Math public: / 一次指派 Math& operator*(Math& rv) return rv.multiply(this); / 二次指派 Math& multiply(Matrix*) cout Matrix * Scalar endl; return *this; Math& multiply(Scalar*) cout Scalar * Scalar endl; return *this; Math& multiply(Vector*) cout Vector * Scalar endl; return *this; ;class Vector : public Math public: /
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年度网络安全防护服务合同2篇
- 2025版果园租赁与农业观光旅游合作协议2篇
- 二零二五年度屋顶防水隔热彩钢瓦安装服务合同样本2篇
- 2025年度绿色建筑PPP项目合作协议2篇
- 二零二五年度洗衣店加盟商合同范本3篇
- 脚手架安全监理细则模版(2篇)
- 统计行政指导工作方案模版(2篇)
- 低压配电室操作规程(2篇)
- 二零二五年度新型环保建筑材料采购销售合同范本3篇
- 二零二五年度昆明公租房电子合同租赁合同签订与租赁双方责任划分3篇
- 法理学课件马工程
- 《玉米种植技术》课件
- DB51-T 5038-2018 四川省地面工程施工工艺标准
- 第47届世界技能大赛江苏省选拔赛计算机软件测试项目技术工作文件
- 2023年湖北省公务员录用考试《行测》答案解析
- M200a电路分析(电源、蓝牙、FM)
- 2024-2030年全球及中国洞察引擎行业市场现状供需分析及市场深度研究发展前景及规划可行性分析研究报告
- 建筑工程施工图设计文件审查办法
- 置业顾问考核方案
- 吉林市2024-2025学年度高三第一次模拟测试 (一模)数学试卷(含答案解析)
- 自考《英语二》高等教育自学考试试题与参考答案(2024年)
评论
0/150
提交评论