面向对象程序设计方案理论

上传人:xt****7 文档编号:183974948 上传时间:2023-01-31 格式:PPT 页数:80 大小:130.50KB
返回 下载 相关 举报
面向对象程序设计方案理论_第1页
第1页 / 共80页
面向对象程序设计方案理论_第2页
第2页 / 共80页
面向对象程序设计方案理论_第3页
第3页 / 共80页
点击查看更多>>
资源描述
11.1面向对象的程序设计方法基础1.2对象和类1.3继承性1.4重载1.5多态性2 面向对象的程序设计方法(Object Oriented Programming)简称为OOP,它的基本元素是类(Class)和对象(Object)。使用对象模拟自然的或抽象的实体,对用户掩盖了实现的复杂性(封装),并且能使程序员付出尽可能小的代价,获得尽可能大收益(继承),提高软件的开发效率。3 类是对事物的特性及操作的抽象描述,对象是类的实体。从C语言的角度来看,类是结构的自然演化,类就是包含数据声明和函数声明的结构。类既包含了数据又包含了代码,对类中成员的存取是受控制的,这一控制不仅针对数据,也针对代码,类的这个特性被称为封装。4计算过程的演变:手工计算全部手工和脑力完成计算器(面向过程)部分借助非人力因素,但仍需对过程进行控制和管理计算机(面向对象)完全借助非人力因素,运算一旦开始,可以无需人工的介入5特性:脚个数物理位置长度宽度高度形状操作:搬动改造“桌子”类6class Counter long count;public:void SetValue(long);long GetValue();关键字class引导类声明Counter是类标识符类体分号7类是一个模板,就象数据类型一样,使用的时候必须定义类变量。定义类变量称为类的实例化,类的实例化变量就是对象。void main()Counter people;long value;people.SetValue(0);value=people.GetValue();对象是具有某一个类所描述的共性的,但又有各自特性的个体。8类的成员的使用者有三类:1.类本身2.一般用户3.派生类每种使用者权限不同,对应与不同的使用权限,有不同的关键字说明。9类本身(或类的友元)可以存取类的私有成员。派生类不能存取其父类的私有成员。因为类必须在程序中使用,所以类必须至少有一个非私有的成员。类成员的存取控制缺省为私有类型。10类私有成员(续)class PrivateClass long value;void f1();void f2();void main()PrivateClass object;long l=object.value;object.f1();object.f2();提问:上述程序可以达到预期效果吗?11在程序中使用给定类的对象,必须能存取成员数据、成员函数或两者。为使这些成员在程序中可以被存取,必须在类中声明公有部分。在公有部分定义的内容允许被其他对象无限制地存取。通常可以有控制地使用公有成员存取私有数据,调用私有成员函数完成工作。12class PublicExamplepublic:int variable;void function();void main()PublicExample object;int i=object.variable;object.function();13class A protected:int value_a;class B:public A public:void FB();class C:public B public:void FC();void B:FB()value_a=0;void C:FC()value_a=014class A int value_1;protected:int value_2;void FA_1();public:int value_3;void FA_2();class B:public Apublic:int value_4;void FB();问:在类B的FB函数中可以直接存取的成员有哪些?问:通过类B的对象在程序中可以直接访问的成员有哪些?15特殊类成员1、构造函数(constructor)2、析构函数(destructor)16构造函数是用来建立某给定类的对象的。一个类可以不定义构造函数,也可以定义一个或多个构造函数。编译系统保证类的构造函数先于其他函数被调用。17class Counter long value;public:Counter();Counter:Counter()value=100;void main()Counter c1;return;构造函数Counter()它有什么特点?18class Counter long value;public:Counter();Counter:Counter(int i)value=i;void main()Counter c1(100);return;构造函数Counter()它有什么特点?19class Counter long value;public:Counter()Counter(int i);Counter:Counter()value=100;Counter:Counter(int i)value=i;void main()Counter c1;Counter c2(100);return;20class Counter long value;public:Counter()value=100;Counter(int i=0)value=i;void main()Counter c1;Counter c2(100);问:Counter类是否能包含如上所示的两个构造函数?为什么?21class Counter long value;public:Counter(Counter&);Counter:Counter(Counter&reference)value=reference.value;22void main()Counter object(5);Counter object1=object;这个等号表示复制构造函数void main()Counter object(5);Proc_A(object);把对象作为参数传递,也需要拷贝构造函数。231、缺省构造函数2、有特定初始化值的构造函数3、通过复制另一个对象建立新对象的构造函数241、构造函数没有返回类型2、构造函数与类同名3、同一个类可以有多个构造函数25class Counter long value;public:Counter();class Example int value;public:Counter c;Example();void main()Example e;在本例中,当c对象作为e对象的成员。问:c对象和e对象的构造函数的调用顺序是怎样的?26析构函数在对象不再被使用时,执行一些必须的操作,一般是构造函数的逆操作。一个类只能声明一个析构函数。析构函数是构造函数的逆函数。27class Counter long value;public:Counter();Counter:Counter()printf(“”);析构函数在声明和使用上有什么特点?281、析构函数没有返回类型2、析构函数的命名是在类名前加“”3、一个类只能有一个析构函数4、析构函数没有参数29从编码角度讲,从基类中派生类以较低代价换来了大量的灵活性。一旦产生了可靠的基类,只需要调试派生类中所做的修改即可。派生类从它的父类中继承性质时,可使派生类对它们进行扩展、限制、改变、删除或不做任何修改。所有这些变化归结成两类基本的面向对象技术:性质约束和性质扩展。30class First int value_1;protected:int value_2;public:int value_3;class Second:First int value_4;public:void F2();问:在程序中可以访问的Second类的对象的成员变量有那些?31class First int value_1;protected:int value_2;public:int value_3;class Second:public First int value_4;public:void F2();基类存取限定符32private:如果没有特别说明,private是缺省的限定符。基类中所有可继承的成员在派生类中都变成私有的。public:基类中所有public成员在派生类中仍为public成员,33class A public:A();class B:public A public:B();如果现在将类B实例化成一个对象,构造函数的调用情况会如何?34类实例化时,需要调用其构造函数。如果该类是派生类,必须调用其父类的构造函数,如果其父类也是派生出来的,重复该过程直至到达非派生的基类。35析构函数的调用顺序与构造函数的调用顺序相反。36class A public:int va;A(int i)va=i;class B:public A public:int vb;B(int i,int j)va=i;vb=j;37class A public:int va;A(int i)va=i;class B:public A public:int vb;B(int j,int i):A(i)vb=j;38void main First c1;Second c2;First*d1=new First;Second*d2=new Second;c1=c2;d1=d2;如果这样则不行:c2=c1;d2=d1;39class A public:int get()return 1;class B:public public:int get()return 2;void main()A a;B b;int i=a.get();int j=b.get();40class A public:int get()return 1;class B:public A public:int get()return 2;void main()A a;B b;int i=a.get();int j=b.get();int k=b.A:get();作用域分辨操作符41使用派生类的主要原因是基类提供了派生类需要的部分特征。常常基类很类似于需要的类,但不完全相同,其中有的函数需要稍微扩展一下。如果在派生类中再次书写整个函数会浪费很多时间。因此,可以充分利用类的继承特性,将函数的功能进行扩充。42假设:有一个类A,它有两个成员函数,其中一个函数的功能的清屏,另一个函数的功能是用“*”画一条直线,直线的长度根据参数决定。现在需要一个新类B,希望它具有清屏的功能,同时具有用“*”画三角形的功能。43*n=7的直线*n=7的三角形44用户常常找到一些基本合乎要求的类,但是它们可能会有一些不受欢迎的行为。这时,可以使用性质约束的方法来使派生类不具有某种功能。45假设:有一个类A,同上例。有一个类B,具有用“*”画三角形的功能,但是它每次画三角形之前都会先清屏。现在需要一个新的类C,希望它具有类B画三角形的功能,但是在画三角形之前不会自动清屏。同时它依然保留单独清屏的功能。46C+语言中,一个类的父类并不只局限于一个,实际上可以有多个,派生类可以从每个父类中继承性质。当然,这种继承性增加了语言和编译器的复杂性,但相比之下益处更多。多重继承大大增加了类继承的灵活性。47假设:有一个类A,具有单独清屏的功能。有一个类B,具有用“*”画直线的功能,但是没有清屏的功能。现在需要一个新的类C,希望它具有用“”画三角形的功能,又具有单独清屏的功能。48class A;class B;class C:public A,public B public:C(int i,int j,int k)C:C(int i,int j,int k):B(j),A(i);构造函数的调用次序是怎样的?49class A public:int value;class B:public A;class C:public A class D:public B,public C public:int get()return value;这个value值从何而来?50class A public:int value;class B:public virtual A;class C:public virtual A class D:public B,public C public:int get()return value;51AAABCBCDD52在OOP中,简洁性是很重要的。用户使用系统时对系统了解得越少越好,调用函数时需要的细节越少越好(参数的个数和类型)。如果函数能够接受各种类型的参数,由编译器区分细节,则会很方便。这个目的在C+中可以达到。但是重载并不是一个全新的概念。531、函数重载2、操作符重载非成员函数重载成员函数重载所谓重载就是同一个符号在不同的上下文中代表不同的含义。54void Display(char*string)void Display(long value)void Display(double value)void main()Display(“nPrint this,please!”);Display(123456789);Display(3.14159);55void Display(char*string)void Display(long value)void Display(double value)void main()Display(333);56void Display(char*string)void Display(long value)void Display(double value)void Display(float value)void main()Display(3.14159);57void Display(float value)int Display(float value)void main()Display(3.14159);不同的返回值不能用来区分重载函数。58class Example int value;public:void Value(int v)value=v;int Value()return value;void main()Example e;e.Value(3);int i=e.Value();59class A public:int foo(int i)return i+1;class B:public A public:int foo(float f)return f+10;void main()B b;int i=b.foo(2);到底应该调用A的foo还是B的foo?60class A public:int foo(int i)return i+1;class B:public A public:int foo(float f)return f+10;void main()B b;int i=b.foo(2);这种情况不构成重载61int f(A&a)return a.foo(3.14159F);void main()B b;int i=f(b);i的结果是多少?62class A public:int foo(int i);class B:public A public:int foo(float f)int foo(int i)return A:foo(i);void main()B b;int i=b.foo(2);int j=b.A:foo(2);int k=b.foo(3.14);63参数匹配问题既重要有复杂。编译器遇到对重载函数的调用时,必须确定调用哪个函数。如果能找到参数完全匹配的函数,自然没问题,找不到时,则找一替代函数。此时,编译器将实在参数与所有重载函数的参数比较,这个过程叫作参数匹配。641、类型转换不是非要不可的。2、有时需要作参数升级。参数可以沿路径charint long float double long double升级。3、参数转换是可以的。参数可以根据标准或用户定义的转换规则进行转换。65class Example int value;public:void Value(int v)value=v;int Value()return value;void main()Example e(?);e.Value(100+e.Value();如果能这样:e=e+100;既直观又方便。66一元操作符 X X.();二元操作符 X Y X.(Y);是一个操作符,但是也可以被理解为一个成员函数。67class Counter int value;public:Counter(int i)value=i;Counter operator!()return Counter(!value);Counter operator+(Counter&c)return Counter(value+c.value);void main()Counter c1(3),c2(5);c1=!c1;c1=c1+c2;68class Counter int value;public:Counter(int i)value=i;Counter operator!(int i)return Counter(!value);Counter operator+(Counter&c)return Counter(value+c.value);放一个不用的参数可以吗?返回类型为什么经常是对象类型。c1+c2+c3+c4+c569名字分裂的目的:使产生重载的符号在编译系统内部有唯一的名字,从而使得它们在目标代码中有不同的入口地址。名字分裂原则:函数名$q符号化的参数表void Counter:Value(int k)CounterValue$qi70多态性是指C+的代码可以根据运行情况的不同执行不同操作。这通常不能由程序员来直接控制,而必须依靠面向对象的程序设计的特性,使对象对自身的运行进行跟踪。多态性是通过类的体系结构来实现的,不过,只有类成员函数可以具有多态性,而不是整个类都具有多它性。71class A public:void foo();class B:public A public:void foo();int f(A&a)return a.foo();void main()B b;f(b);这个地方最终调用的是哪个类的foo函数?为什么?72如果在上例中需要f函数根据形式参数中传递进来的对象的类型自动调用该类的foo函数,则需要激活C+的迟后联编的功能,使程序在执行的过程中自动选择相应的函数。73class A public:virtual void foo();class B:public A public:virtual void foo();int f(A&a)return a.foo();void main()B b;f(b);这时将根据实际的参数类型来选择相应的函数。74声明为virtual的函数为虚函数。通过声明函数为virtual,来人为指定迟后联编。迟后联编只能用于类等级中的对象。对于不被任何类继承的类,声明其函数为虚函数,从语法上来讲是正确的,但是会引起不必要的运行时刻开销。751、虚函数的参数个数与类型。2、虚函数的传递。使用虚函数后,派生类中的函数可以覆盖原有基类中函数的功能,这被称为函数覆盖。构成函数覆盖的条件是:76由虚函数的传递性可以看出,出现在类等级顶部及其附近的类常常有多个空的虚函数。如果一个类只有空虚函数,实例化这样的类有意义吗?但是,这种实例化是允许的,其结果是得到一个占有内存却不做任何操作的无用的对象。为了避免这种情况的发生,C+中引进了可以被继承但是不能实例化的抽象类。77至少包含一个纯虚函数的类被称为抽象类。class A public:virtual void foo()=0;注意纯虚函数的定义方法。78class A public:virtual void foo()=0;void main()A a;a.foo();注意:抽象类不能实例化。79class A public:virtual void foo()=0;class B:public A public:virtual void foo();void main()B b;b.foo();注意:纯虚函数一定要被覆盖。80class A public:virtual void foo();class B:public A public:virtual void foo();int f(A&a)return a.A:foo();void main()B b;f(b);此处调用的依然是A:foo()函数,而不是B:foo()函数
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!