C++ 面对对象程序设计 授课老师:.

Slides:



Advertisements
Similar presentations
第8章 继承和派生 8.1 继承与派生 8.2 派生类对基类成员的访问 8.3 派生类的构造函数与析构函数 8.4 多重继承与虚基类.
Advertisements

课程 要求 参考 书目 课程 内容 课程 练习.
面向对象的C++程序设计基础 第 4 章 继承与派生.
第四章 继承与派生 Chapter 4 Inheritance and Derivation
第九讲 类与对象 (I)面向对象基础.
第6章 多态性与虚函数.
7.2 访问控制 —— 公有继承 公有继承练习 //Point.h #ifndef _POINT_H #define _POINT_H class Point { //基类Point类的定义 public: //公有函数成员 void initPoint(float x = 0, float.
内容提要 代码重用 类的继承 多态 抽象类 多重继承 虚拟继承. 常宝宝 北京大学计算机科学与技术系
類別與物件 Class & Object.
计算机可视化编程 基于Visual C++6.0的面向对象编程 第 四 讲 主讲教师:隋振                学时:32.
C++面向对象程序设计 第八章 继承和派生.
第12章 组合与继承 欢迎辞 第14次见面!.
面向对象程序设计 第三章 C++面向对象程序设计 武汉大学 赵小红.
第四章 继承和派生类 汽车 专用汽车 运输汽车 货车 客车 消防车 洒水车 最普遍、最一般,可以自行驱动 含有汽车的特性,同时与汽车有不同
第14章 c++中的代码重用.
C++语言程序设计 第七章 继承与派生 清华大学 郑 莉.
第11章 类的继承和派生 继承是面向对象程序设计方法的四个基本特征之一,是程序代码可重用性的具体体现。
全国计算机等级考试 二级基础知识 第二章 程序设计基础.
第6章 多态性与虚函数.
第10讲 Java面向对象编程基础(4) 教学目标 主要内容.
类和对象 潘荣江 山东大学计算机科学与技术学院
第3章 继承和派生.
授课老师:龚涛 信息科学与技术学院 2018年4月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第10章 C++面向对象程序设计 本章导读 C语言是一种结构化程序设计语言,它是面向过程的,在处理较小规模的程序时一般比较容易实现,而当程序规模较大时,C语言就显示出了它的不足。在这种情况下C++应运而生,C++语言是从C语言演变而来的,它保留了C语言的所有优点,同时也增加了面向对象的功能。现在C++已成为程序设计中应用最广泛的一种语言。
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
第12讲 多继承与虚基类 多继承 虚基类.
走进编程 程序的顺序结构(二).
辅导课程六.
第9章 类和对象(一) 9.1 面向对象的基本概念 9.2 类与对象的声明和定义 9.3 成员函数 9.4 对象的访问 9.5 对象的存储.
第1章 C++基础.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第八章 继承与派生 丘志杰 电子科技大学 计算机学院 软件学院.
第十一章 继承和派生. 主讲教师:全红艳 第十一章 继承和派生.
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第16章 虛擬與多形 16-1 虛擬函數 16-2 純虛擬函數與抽象類別 16-3 多形 16-4 虛擬繼承與虛擬解構子.
C++大学基础教程 第9章 继承与派生 北京科技大学.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++面向对象程序设计 谭浩强编著 授课教师:姬广永 QQ: 学习网站:
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
第12讲 多继承与虚基类 多继承 虚基类.
C++语言程序设计 C++语言程序设计 第五章 函数 第十一组 C++语言程序设计.
$9 泛型基础.
C++复习3 ----类的继承与派生.
C#面向对象程序设计 $6 深入理解类.
C++语言程序设计 第四章 类与对象.
第13讲 多态 友员函数 多态性与虚函数 纯虚函数和抽象类.
第10讲 构造函数和析构函数 构造函数 析构函数 This 指针.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Object-Oriented Programming in C++ 第二章 类和对象
第九节 赋值运算符和赋值表达式.
C++程序设计基础 主讲人:谢昕 华东交通大学信息工程学院 第十~十二讲 多态性和虚函数 2005年春季学期.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计教程 第8章 继承与派生 第8章 继承与派生 制作人:杨进才.
辅导课程十五.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++与数据结构简明教程 第五章 类和对象.
谭浩强编著 C++面向对象程序设计 授课教师:姬广永 学习网站:
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第十二讲 继承 与 派生.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Presentation transcript:

C++ 面对对象程序设计 授课老师:

第10章 继承 本章要点 10.1 继承与派生 10.2 支配规则和赋值兼容性 10.3 虚基类

本章要点 继承与派生的概念 派生类的定义语句格式及使用方法 冲突、支配规则、赋值兼容性的概念 虚基类的概念 虚基类的语句定义格式及使用方法 静态成员的定义格式、初始化方式及作用域

10.1.1继承与派生的基本概念 1.继承与派生的定义 在面相对象程序设计中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的说明。以原有的类为基础产生新的类,我们就说新类集成了原有类的特性,也可以说从原有类派生出新类。原有类称为基类或父类,产生的新类称为派生类或子类。 2.单一继承 3.多重继承

10.1.2派生类的定义 在C++中,定义派生类的一般语法为: class <派生类名> : <继承方式1> <基类名1>,﹝,…,<继承方式n> <基类名n> ﹞ { <派生类新定义成员> }; 声明中的“基类名”是已有的类的名称,“派生类名”是继承原有类的特性而生成的新类的名称。

10.1.2派生类的定义 在派生过程中,派生出来的新类也可作为基类来继续派生新的类,此外,一个基类可以同时派生出多个派生类。也就是说,一个类从父类继承来的特征也可以被其他新的类所继承,一个父类的特征,可以同时被多个子类继承。 A B C Y Z X

<派生类构造函数体> //派生类新增成员的初始化 } 10.1.3派生类的构造函数与析构函数 1.构造函数 派生类的构造函数需要以合适的初值作为参数,隐含调用基类和新增对象成员的构造函数,来初始化它们各自的数据成员,然后加入新的语句对新增普通数据成员进行初始化。 派生类构造函数的一般语法规则为: <派生类名>::<派生类名> (形参表) : <基类名1>(实参表1), ﹝,…,<基类名n>(实参表n)﹞ { <派生类构造函数体> //派生类新增成员的初始化 }

【例10-1】 派生类构造函数实例 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class A { public: A() a=0; cout<<"类A的默认构造函数被调用"<<endl; } //*程序接下页

程序接上页 A(int i) { a=i; cout<<"类A的构造函数被调用"<<endl; } ~A() void Print() const { cout<<a<<","; int Geta() return a; private: int a; };

程序接上页 class B: public A { public: B() b=0; cout<<"B的默认构造函数被调用"<<endl; } B(int i,int j,int k); ~B() cout<<"B的析构函数被调用"<<endl; void Print(); private: int b; A aa; };

程序接上页 B::B(int i,int j,int k) { b=k; cout<<"B的构造函数被调用"<<endl; } void B::Print() A::Print(); cout<<b<<","<<aa.Geta()<<endl; void main() B bb[2]; bb[0]=B(1,2,5); bb[1]=B(3,4,6); for(int i=0; i<2; i++) bb[i].Print(); getchar();

程序运行结果

2析构函数 当对象被删除时,派生类的析构函数被执行。由于析构函数也不能被继承,因此在执行派生类的折构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数时的顺序正好相反。

【例10-2】 派生类析构函数实例 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class M { public: M() m1=m2=0; } M(int i,int j) m1=i; m2=j; } // 程序接下页

程序接上页 ~M() { cout<<"M的析构函数被调用"<<endl; } void print() { cout<<m1<<","<<m2<<","; private: int m1, m2; }; class N: public M { public: N() { n=0; N(int i,int j,int k); ~N() { cout<<"N的析构函数被调用"<<endl;

程序接上页 void print() { M::print(); cout<<n<<endl; } private: int n; }; N::N(int i,int j,int k):M(i,j),n(k) {} void main() N n1(2,3,4),n2(5,6,7); n1.print(); n2.print(); n1.~N(); n2.~N(); getchar();

程序运行结果如图

10.2冲突、支配规则和赋值兼容性 10.2.1冲突 为了介绍冲突的概念,先看一个例子。 【例10-3】 定义描述圆的类Circle,定义描述矩形的类Rectangle,描述圆的类与描述矩形的类作为基类,多重派生出圆柱体类Cylinder,在Rectangle类中用矩形中心坐标(x,y)、高(High)与宽(Width)作为类的数据成员,讨论多重继承中基类成员的冲突问题。

程序接上页 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class Circle //定义描述圆的基类 { protected: float x, y, r; //(x,y)为圆心坐标,r为半径 public: Circle(float a,float b,float c) x=a; y=b; r=c; } float Area() //计算圆的面积 return (r*r*3.14159); };

程序接上页 class Rectangle //定义描述矩形的基类 { protected: float x, y, h, w; //(x,y)为矩形中心坐标,h,w为矩形的高与宽 public: Rectangle(float a,float b,float c,float d) x=a; y=b; h=c; w=d; } float Area() //计算矩形面积 return h*w; };

程序接上页 class Cylinder:public Circle,public Rectangle { private: float Volume; //圆柱体的体积 public: Cylinder(float a,float b,float c):Circle(a,b,c),Rectangle(10,10,c,c) //A { Volume=Area()*h;} ∥B float GetV() {return Volume;} void Show(void) { cout<<"x="<<x<<'\t'<<"y="<<y<<endl;} ∥C }; void main() { Cylinder cy(3,3,2); cy.Show(); cout<<"Volume="<<cy.GetV()<<endl; getchar(); }

程序分析 从上例可以看出,在派生类中使用两个基类中同名函数Area()或同名数据成员(x,y)时会产出编译性错误,出错的原因是发生了同名冲突。由此,给出如下有关冲突的定义: 派生类使用基类中同名成员时出现不唯一称为冲突。 解决冲突的方法是使用作用域运算符“::”指明同名成员属于哪一个基类,即: <基类名>::<成员名>

10.2.2支配规则 在C++中,允许派生类中新增加的成员名与其基类的成员名相同,这种重名并不产生冲突。若不使用作用域运算符,则派生类中定义的成员名优于基类中的成员名,这种关系称为支配规则。 在【例10-3】的派生类Cylinder中,新增数据成员(x,y,z)表示圆柱体中心坐标。并从基类Rectangle中删除(x,y)。 修改后程序如下:

class Circle //定义描述圆的基类 { protected: float x, y, r; //(x,y)为圆心坐标,r为半径 程序 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class Circle //定义描述圆的基类 { protected: float x, y, r; //(x,y)为圆心坐标,r为半径 public: Circle(float a,float b,float c) x=a; y=b; r=c; }

程序 float Area() //计算圆的面积 { return (r*r*3.14159); } }; class Rectangle //定义描述矩形的基类 protected: float x, y, h, w; //(x,y)为矩形中心坐标,h,w为矩形的高与宽 public: Rectangle(float c,float d) h=c; w=d; float Area() //计算矩形面积 return h*w;

程序 class Cylinder:public Circle,public Rectangle { private: float x,y,z,Volume; public: Cylinder(float a,float b,float c,float d):Circle(a,b,d),Rectangle(d,d) x=a; y=b; z=c; Volume=Circle::Area()*h; } float GetV() return Volume;

void Show() { cout<<"x="<<x<<'\t'<<"y="<<y<<'\t'<<"z="<<z<<endl; } }; void main() Cylinder cy(3,3,3,2); cy.Show(); cout<<"Volume="<<cy.GetV()<<endl; getchar(); 程序执行后输出结果如下: x=3 y=3 z=3 Volume=25.1327

10.2.3赋值兼容规则 赋值兼容规则指的是在需要基类对象的任何地方都可使用公有派生类的对象来替代。通过公有继承,派生类得到基类中除构造函数、析构函数之外的所有成员,并且所有成员的访问控制属性也和基类完全相同。因此,公有派生类已经具备基类的所有功能。 赋值兼容规则中所指的替代包括以下3种情况: ①派生类的对象可以赋值给基类对象。 ②派生类的对象可以初始化基类的引用。 ⑧派生类对象的地址可以赋给基类类型的指针。

【例10-5】 赋值兼容规则应用举例 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class A { public: void f() //公有函数 cout<<"A::f()"<<endl; } }; class B:public A //A的公有派生类B的声明 void f() cout<<"B::f()"<<endl; //对A中的f()进行覆盖

class D:public B { public: void f() cout<<"D::f()"<<endl; //对B中的f()进行覆盖 } }; void fun(A *p) //参数为指向基类对象的指针 p->f();

void main() { A a; B b; D d; A *p; //声明A类指针 p=&a; //A类指针指向A类对象 fun(p); p=&b; //A类指针指向B类对象 p=&d; //A类指针指向D类对象 getchar(); } 运行结果为: A::f()

10.2.4对基类和对象成员的几点说明 (1)任一基类在派生类中只能继承一次。 (2)基类成员与对象成员在使用上的差别。把一个类作为派生类的基类或将一个类的对象作为另一个类的成员,从程序的执行效果上看是相同的,但在使用上是有区别的: 派生类中可直接使用基类的成员(访问权限允许的话); 使用对象成员时,必须在对象名后加上成员运算符“.”和成员名。

10.3虚基类 在派生类的对象中,同名成员在内存中同时拥有多个拷贝,可以使用作用域分辨符来惟一标识并分别访问它们,也可以将共同基类改置为虚基类,这时从不同的路径继承过来的该类成员在内存中只拥有一个拷贝,这样就解决了同名成员的惟一标识问题。 虚基类说明形式为: virtual <继承方式> <基类名> 其中,virtual是虚基类的关键字,关键字virtual与继承方式的位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名起作用。

【例10-6】虚基类应用举例 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class A { public: int a; void fun() cout<<"a="<<a<<endl; } };

class B:virtual public A //A为虚基类,派生B类 { public: //新增外部接口 int b; }; class C:virtual public A //A为虚基类,派生C类 { public: int c; class D:public B,public C //派生类D声明 { int d; void f(int i) { d=i; } void g() { cout<<"d="<<d<<endl;

void main() { D t; t.a=3; //使用直接基类 t.fun(); getchar(); } 运行结果为: a=3 说明:在D类中,通过B,C两条派生路径继承来的基类A中的成员a和fun()只有一份拷贝,在D派生类中只有惟一的数据成员a和函数成员fun()。

10.4静态成员 静态数据成员 静态数据成员在内存中只有一个拷贝。使用静态数据成员可以节省内存空间。静态数据成员的值对于每一个对象都是一样的。 静态数据成员的定义格式如下: static <数据类型> <变量名>; 静态数据成员初始化格式如下: <数据类型类名>::<静态数据成员名>=<初始值>; 引用静态数据成员的格式如下: <类名>::<静态数据成员名>

10.4.2静态成员函数 静态成员函数也是属于该类的所有对象,而不是属于任何对象。静态成员函数的引用不用对象名,而是类名。 静态成员函数一般用于操作该类中的静态数据成员。在静态成员函数的实现中不能直接引用类中的非静态成员,但可以引用类中的静态成员。如果静态成员函数中需要引用非静态成员时,只能通过对象来引用。 静态成员函数调用格式为: <类名>::<静态成员函数名>(<参数表>)

【例10-7】 静态成员函数应用举例 #include "stdafx.h" #include "stdio.h" #include "iostream.h" class Vc { int A; static int B; //静态数据成员说明 public: Vc(int a) A=a; B+=a; }

static void Display(Vc c) { cout<<"A="<<c.A<<",B="<<B<<endl; } }; int Vc:: B=20; //静态数据成员初始化 void main() Vc A(20),B(40); Vc::Display(A); Vc::Display(B); getchar(); 程序运行结果是: A=20,B=80 A=40,B=80

本章小结 本章介绍了类的继承性。面向对象的三大特性是封装性,继承性和多态性。所谓继承是指从已有类出发建立新的类,使新类部分或全部地继承已有类的成员。通过继承已有的一个或多个类产生一个新类称为派生。使用继承与派生可以减少程序编写的工作量,还能使程序更加易于维护。派生类使用基类中同名成员时出现不唯一称为冲突。在多重派生的过程中,欲使公共的基类在派生类中只有一个拷贝,可将此基类说明成虚基类。本章最后还介绍了静态成员,静态数据成员不是属于任何对象,它属于该类的所有对象。静态成员函数和静态数据成员一样,也是属于该类的所有对象,而不是属于任何对象。