资源预览内容
第1页 / 共127页
第2页 / 共127页
第3页 / 共127页
第4页 / 共127页
第5页 / 共127页
第6页 / 共127页
第7页 / 共127页
第8页 / 共127页
第9页 / 共127页
第10页 / 共127页
亲,该文档总共127页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Lecture Notes on Object-Oriented Technology (Programming & Design) (Fall 2010, Bachelor of Computer Science)Duan shihong duanshies.ustb.edu.cn Office: Room 1203A ,Information Building,第八讲 继承与多态性(I),软件复用及其途径 继承:泛化的实现 继承中的对象初始化与收尾 多继承与重复继承 继承的实例:纸牌游戏 主题讨论:存储模型,与继承相关的两个设计原则,两种is-a关系 分类(classification):描述实例与类型之间的关系。 Tommy is a cat. 泛化(generalization):描述类型与类型之间的关系(子类型关系)。 Cats are animals. 注意它们的区别 泛化关系具有传递性;而分类关系不具有传递性。 继承所指的is-a关系是指泛化,而不是分类。 有学者提出新名词:用kind-of关系代替is-a关系。 The cat ia a kind of animals.,继承是is-a关系在程序中的实现 is-a关系:在问题空间中描述概念与概念之间的关系。 利用现有概念来定义一个新的概念。 继承关系:在解空间中描述类与类之间的关系。 利用现有的类来定义一个新的类。 软件复用的思想 面向对象设计的一个重要指导原则是:不要每次都从头开始定义一个新的类,而是将这个新的类作为一个或若干个现有类的泛化或特化。,继承机制,class Xint i; public:X( ) i = 0; void f(); ;class Yint j; public:X x;Y( ) i = 0; ;,main() Y y;y.x.f(); ,(composition),继承,class Box public: int width, height; void SetWidth(int);void SetHeight(int); ;,class ColoredBox:public Box public: int color; void SetColor(int); ;,ColoredBox cb; void main() cb.SetWidth(5); cb.SetHeight(5); cb.SetColor(6); ),class Cleanser private: string s;protected: void append(string a) s += a; public: Cleanser() s = “Cleanser”;void dilute() append(“ dilute()“); void apply() append(“ apply()“); void scrub() append(“ scrub()“); void print() coutsscrub(); /! Detergent *d = new Cleanser(); /! D-foam();,incompatible types,静态类型 vs 动态类型 静态类型:声明obj时的类型(在编译时确定的类型)。 动态类型:在运行时某一时刻与obj相关联的对象的类型。 由于基本类型的静态与动态类型没有区别,故只需讨论引用类型。 动态类型必须是静态类型的子类型!,Cleanser *c = new Detergent();,c的静态类型,c的动态类型,对继承的狙击 有时候并不希望由客户程序自定义的子类代替某些类! Java里有很好的机制将一个类定义为final的或者将一个成员定义 为final的。 C+里如何实现禁止类被派生? 解决方案 1 构造函数声明为私有的。如果用户从该类派生一个类,那么在编译阶段就会得到一个不能访问私有成员函数的错误信息。 2 创建伪造的构造函数:静态,返回的是对象指针 3 注意:用户在使用完该类对象后需要调用delete,释放资源。也可使用智能指针。,class ClxNotBase public: ClxNotBase(); private: ClxNotBase(); ClxNotBase(const ClxNotBase,构造函数私有,禁止派生,如果把类的构造函数声明为私有的,那么我们就无法构造这个类的对象,,class ClxNotBase public: ClxNotBase(); static ClxNotBase * NewlxNotBase(); static ClxNotBase * NewlxNotBase(const ClxNotBase ,创建伪造的构造函数,如果把类的构造函数声明为私有的,那么我们就无法构造这个类的对象,,两种不同的继承模式 重定义(overriding):仅重定义父类的操作而不引入新特征。 是比扩充更为重要、更加常见的继承模式。 子类型的接口与父类型完全相同,两者是完全相同的类型。 扩充(extending):引入父类所没有的新特征。 子类型与父类型有区别:更加丰富的内容,是父类型的特例。 Java语言的保留字extends表明了这种继承。 实际应用通常是上述两种方式的结合。,继承的模式,重定义的继承模式(is-a),扩充的继承模式(is-like-a),注意圆与点之间 关系不是has-a关系,将圆看作一种 带有半径的点,C+派生类的定义格式,class 派生类名:继承方式 基类名 public:/派生类公有成员private:/派生类私有成员;,派生类只有 一个直接基 类为单继承,例: 定义基类Pen,class Pen public:enum ink off,on;void set_status (ink);void set_location (int, int); private:int x; int y;int status; /状态;,定义派生类(彩色钢笔),class CPen: public Pen public:void set_color(int); private:int color; ;,color,set_color,继承概念1 - 继承方式,三种继承方式: 公有继承(public), 私有继承(private), 保护继承(protected),不同继承方式的影响主要体现在: 派生类成员对从基类继承的成员的访问控制。 派生类对象对从基类继承成员的访问控制。,继承方式继承的访问控制,不同的继承方式使得派生类从基类继承的成员具有不同的访问控制权限,以实现数据的安全性和共享性控制。派生类成员(继承的成员自增加的成员)的访问权限: 1)inaccessible(不可访问) 2)public 3)private 4)protected,公有继承(public),基类的public和protected成员的访问属性在派生类中保持不变,但基类的private成员不可访问。 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能访问基类的private成员。 通过派生类的对象只能访问基类的public成员。,参见程序derive工程,公有继承举例,class Point /基类Point类的声明 public: /公有函数成员void InitP(float xx=0, float yy=0)X=xx;Y=yy;void Move(float xOff, float yOff)X+=xOff;Y+=yOff;float GetX( ) return X;float GetY( ) return Y; private: /私有数据成员float X,Y; protected: /受保护数据成员int a,b; ;,class Rectangle: public Point /派生类声明 public: /新增公有函数成员void InitR(float x, float y, float w, float h)InitP(x,y);W=w;H=h;/调用基类公有成员函数float GetH( ) return H;float GetW( ) return W; private: /新增私有数据成员float W,H; ;,InitP,public,Move,public,GetX,public,GetY,public,X,Y,inaccessible,a,b,protected,X=2;可否?,a=2;可否?,#include #includeint main( ) Rectangle rect;rect.InitR(2,3,20,10);/通过派生类对象访问基类公有成员rect.Move(3,2); cout , ,rect.GetH( ),rect.GetW( )endl;return 0; ,rect.GetX ( ),rect.GetY( ),
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号