C++教程第08章 继承与派生-5-7

合集下载

C++第08章+继承与派生

C++第08章+继承与派生

10
第八章 继承与派生
基类成员在派生类中的存取权限
(1) 无论何种派生方式,基类的私有成员在派生类中不 能访问;基类的保护成员和公有成员在派生类内部可进 行存取。 (2) 私有派生使基类的保护成员和公有成员都成为派生 类的私有成员,在派生类中可直接访问,在类外不能访 问。一般情况下,私有派生使用较少,它中止了基类功 能的进一步派生。 (3) 保护派生使基类的保护成员和公有成员都成为派生 类的保护成员,在派生类中可直接访问,在类外不能访 问。它与私有派生的不同表现在进一步派生时。 (4) 公有派生使基类的保护成员和公有成员在派生类中 不变,仍然是保护成员和公有成员。在类外可访问公有 11 成员,不可访问保护成员。
26
第八章 继承与派生
3. 赋值兼容规则 派生类对象间的赋值操作依据下面的原则: (1) 如果派生类有自己的赋值运算符的重载定义, 即按该重载函数处理。 (2) 派生类未定义自己的赋值操作,而基类定义了 赋值操作,则系统自动定义派生类赋值操作,其中 基类成员的赋值按基类的赋值操作进行。 (3) 二者都未定义专门的赋值操作,系统自动定义 缺省赋值操作。
生类继承的成员仍是某类的友元。
25
第八章 继承与派生
2. 静态成员的继承 如果基类的静态成员是公有的或是保护的,则 它们被其派生类继承为派生类的静态成员。即: (1) 这些成员通常用<类名>::<成员名>方式引 用或调用(在派生类的访问属性为public时)。 (2) 这些成员无论有多少个对象被创建,都只有一 个拷贝。它为基类和派生类的所有对象共享。
13
第八章 继承与派生
例:
雇员
兼职技术人员
管理人员
销售人员
销售经理

C语言程序设计基础-实验八继承与派生类

C语言程序设计基础-实验八继承与派生类

实验八继承与派生类1.实验目的要求(1)掌握单继承程序设计的基本方法。

(2)掌握多继承程序设计的基本方法。

2.实验设备电脑一台,Microsoft Visual C++ 6.03.实验内容(1) 下面程序定义一个vehicle类,并派生出car和truck两个派生类。

#include<iostream.h>class vehicle{protected:int wheels;double weight;public:void initialize(int whls, double wght);int get_wheels() { return wheels; }double get_weight() { return weight; }double wheel_loading() { return weight/wheels; } };class car: public vehicleprivate:int passenger_load;public:void initialize(int whls, double wght, int people =4);int passengers() { return passenger_load; }};class truck: public vehicle{private:int passenger_load;double payload;public:void init_truck(int number =2, double max_load =24000.0);double efficiency();int passengers() { return passenger_load; }};void vehicle::initialize(int whls, double wght){wheels=whls;weight=wght;}void car::initialize(int whls, double wght, int people){wheels=whls;weight=wght;passenger_load=people;void truck::init_truck(int number, double max_load){passenger_load=number;payload=max_load;}double truck::efficiency(){return payload/(payload+weight);}void main(){vehicle bicycle;bicycle.initialize(2,25);cout<<"the bicycle has "<<bicycle.get_wheels()<<" wheels.\n";cout<<"the bicycle weighs "<<bicycle.get_weight()<<" pounds.\n";cout<<"the bicycle's wheel loading is "<<bicycle.wheel_loading()<<" pounds per tire.\n\n";car audi;audi.initialize(4,3500.0,5);cout<<"the audi has "<<audi.get_wheels()<<" wheels.\n";cout<<"the audi weighs "<<audi.get_weight()<<" pounds.\n";cout<<"the audi's wheel loading is "<<audi.wheel_loading()<<" pounds per tire.\n\n";truck jief;jief.initialize(18,12500.0);person person teacher graduate in-service_graduatejief.init_truck(2,33675.0);cout<<"the jief has "<<jief.get_wheels()<<" wheels.\n";cout<<"the jief weighs "<<jief.get_weight()<<" pounds.\n";cout<<"the jief's efficiency is "<<100.0*jief.efficiency()<<" percent.\n";}[基本要求]● 上机录入、调试上面程序。

C继承和派生

C继承和派生

C继承和派生简单来说:有两个类A和B,A是父类,B是子类。

那么就可以说:A派生出B,B继承与A。

例:父亲“派生” 出儿子儿子“继承” 自父亲派生和继承,本质是相同的,只是从不同角度来描述他们而已。

继承和派生在UML中的表示:注意是空心三角形从子类【派生的类】指向父类【被继承的类】父类,也被称为”基类”除了”构造函数“ 和”析构函数“,父类的所有成员函数,以及数据成员,都会被子类继承!假如已经定义好了父类Father,里面定义好私有数据成员name 和age,和公有的构造函数、成员方法description等。

当子类Son 要继承父类Father时,需要包含”父类的头文件“,定义方式如下:公有继承方式#include "Father.h" // 包含父类的头文件class Son : public Father {// 详细见下面全部代码}假如子类Son要调用自定义的重载构造函数是:1.会先调用父类的构造函数,用来初始化父类继承的数据,2.再掉用自己的构造函数,用来初始化自己定义的数据。

例:Son::Son(const char *name, int age, const char *game) : Father(name, age) {// 没有体现父类的构造函数, 那就会自动调用父类的默认构造函数this->game = game; // 子类自己定义的数据成员}注意一:子类的成员函数,不能访问从父类继承的private成员例:在子类Son中,this->name = name;或者cout << age << endl;都是错误的。

但子类可以访问父类的成员函数,如cout << getName() << getAge() << endl;都是正确的。

注意二:子类对象调用方法时,现在自己定义的方法中去寻找,如果有,就调用自己定义的方法;如果找不到,就到父类的方法中去找,如果有,就调用父类的这个同名方法;如果在父类中找不到,就发生错误!例:父类和子类都定义了description方法,子类Son去调用这个方法,会优先在自己的方法里去找来调用,如果没有,再去父类里找;也没有的话就报错。

C++继承与派生

C++继承与派生

8
8.2.3 派生类对象的初始化和撤销
1.派生类对象的初始化 在派生类对象中包含一个匿名的基类对象,在创建和初始化派生类对象 时,系统按照一定的顺序进行:先初始化该匿名的基类对象,然后再初始化派生 类自己的新增成员。 匿名基类对象的初始化由基类的构造函数来完成,派生类的构造函数会 调用基类的构造函数来完成匿名基类对象的初始化,默认情况是调用基类无参数 的构造函数,如果要调用其他带参数的构造函数,则必须在派生类构造函数的成 员初始化列表中指出。派生类构造函数的一般格式为:
name offertel dept no sal specialty一
Programmer类对象内存影像
5
8.2.2 继承方式以及派生类成员的访问
从基类继承的成员也可能会在两个地方被访问:①在派生类内部,派 生类新增的函数可能会访问从基类继承的成员。②在派生类的外部,通过派生 类对象来访问从基类继承的成员。对从基类中继承的成员的访问,受到其在派 生类中的访问控制方式的限制,而基类的成员在派生类中的访问权限由该成员 在基类中的访问控制方式和派生类的继承方式共同决定的。 继承方式在定义派生类时指出,如未指出,则默认为private。继承方 式对基类成员在派生类中的访问控制方式的影响如表所示。
A B
C 图8-5 多级继承关系
Байду номын сангаас
13
8.3 多重继承
14
8.3.1 多重继承的定义
在定义多重继承的派生类时,需要给出两个或两个以上的直接基类,其格式为: class <派生类名>:[<继承方式>]<基类名>,[<继承方式>]<基类名>,......{ <派生类新增成员说明表> }

总结-----c 之继承和派生

总结-----c  之继承和派生

继承和派生一.继承(inheritance):在一个已存在的类的基础上建立一个新的类。

在c++中可重用性是通过继承这一机制实现的。

派生(derived):在已有类的基础上新增自己的特性而产生新类的过程。

共享基类的成员。

派生类不会继承基类的友元关系。

派生类同时也是一个组合:创建一个新类,类中的一个或者多个对象是其他类的成员。

被继承的类称为基类(base class),派生出的类称为派生类(derived class)。

一个派生类可以从一个基类派生,称之为单继承。

也可以从多个基类派生,称之为多继承。

派生过程基类不会作出改变。

派生类则除了继承基类所有可引用的成员外,还可以另外定义新的成员。

继承首先是代码重用的一种机制,但另一个重要的特性在于:继承描述了一组类,这组类在一个相关联的层次上,一个类可以看作是另一个类。

二.继承的目的:实现代码重用。

通过继承机制,可以利用已有的数据类型来定义新的数据类型。

派生的目的:当新的问题出现,原有程序无法解决时,对原有程序进行改造。

三.派生类的声明Class 派生类名:继承方式基类名{派生类新增加的成员声明;}派生类一部分是从基类继承的成员,一部分是在声明派生类时新增加的部分。

四.派生生成过程。

1.吸收基类成员:吸收除构造函数和析构函数外的数据。

2.改造基类成员:声明一个和基类成员同名的新成员,派生类中的新成员就屏蔽了基类同名成员称之为同名覆盖。

这里的屏蔽或者覆盖并不是真正意义上的覆盖,依然可以通过基类名加作用域操作符(::)进行访问。

3.发展新成员:派生类新增加的成员。

新增加的成员需与基类成员不同命。

4.重写构造函数和析构函数:被重新定义的基类函数是虚函数,则称派生类中同名函数为重写。

派生类不会继承基类的构造函数和析构函数。

五.继承方式:继承方式不同影响派生类成员对基类成员访问权限。

1.Pubulic access(公有继承):派生类继承基类的public和protected 且访问属性不变。

C++面向对象程序设计第八章继承与派生

C++面向对象程序设计第八章继承与派生
【例8.5】 多继派生的访问控制 】
13
8.4
派生类的构造函数与析构函数
在产生新的对象时, 都会调用相应的构造函数。 构造函数的作用有两点: (1)为成员变量分配存储空间。 (2)初始化成员变量的值。 派生类的构造函数? 析构函数? 基类的构造函数和析构函数是不能被继承的!
14
8.4.1简单派生类的构造函数
25
8.7继承与组合
在实际的程序开发过程中,使用面向对象的方 法,在建立新类的时候,要弄清新类与已有类 之间的关系 看究竟是 看究竟是ISA关系还是HASA关系? 关系还是 关系? 如果是ISA关系,就要通过继承来产生新的类 如果是HASA关系,就要通过组合来产生新的类
【例8.14】继承与组合示例 】
21
8.5.3多重继承的问题 【例8.10】 多重继承的问题 】
解决的办法之一:在处理变量时通过 基类名加上域作用符的方式 指明要操作的究竟是哪个变量 这样即不符合现实,还浪费了存储空间 解决的办法之二: 采用 虚基类
22
8.5.4虚基类
在继承时通过关键字virtual声明为虚继承, 相应的基类就成了虚基类。
6
8.2
派生类的声明方式及构成
比较这个定义和上一节中给出的undergraduate 定义,很容易发现继承的写法: 默认为private私 默认为 私
有继承 基类名1, 基类名2, class 子类名 : 继承方式 基类名 ,继承方式 基类名 , [继承方式] 父类名 …继承方式 基类名 继承方式 基类名n { 继承方式可以是 public(公有继承) (公有继承) 类的定义体 private(私有继承) (私有继承) protected(保护继承) (保护继承) };

C#语言培训8 类的继承

C#语言培训8 类的继承

继承的单一性
•继承的单一性是指子类只能继承一个父类,不能同时继承多个父类。 •C#不支持多重继承,也就是说儿子只能有一个亲生父亲, •不能同时拥有多个亲生父亲。 •C#中使用接口技术实现多重继承,这个在后面的章节中会具体阐述。
继承的传递性
还可以有子类 汽车
卡车
公汽车
小型卡车
重型卡车
单层
双层
有汽车的特性
访问修饰符——设置访问权限
访问修饰符-示例
class MyAccess { public int x; //在任何地方都可访问 protected int y; //在自身类以及子类可访问 private int z; //在自身类可访问(类的成员默认是private) public MyAccess() { this.x = 10; this.y = 20; this.z = 30; } } class SubAccess : MyAccess { public SubAccess() { this.x = 10; this.y = 20; //this.z = 30; //出错 } } class TestAccess { public void Show() { MyAccess obj = new MyAccess(); obj.x = 100; //obj.y = 200; //出错 //obj.z = 300; //出错
base关键字——调用父类成员
• C#中base关键字在继承中起到非常重要的作用, 它可以和this关键字相比较,大家都知道this代表 当前实例,那么base关键字代表父类,使用base 关键字可以调用父类的构造函数、属性和方法。 使用base关键字调用父类构造函数的语法如下: • 子类构造函数:base(参数列表) • 使用base关键字调用父类方法的语法如下: • base:父类方法();

c课程设计继承与派生

c课程设计继承与派生

c 课程设计继承与派生一、教学目标本章节的教学目标是让学生掌握C语言中继承与派生的概念,理解并能够运用继承与派生编写C++程序。

具体目标如下:1.知识目标:理解继承与派生的概念及其在C++程序设计中的应用。

掌握继承与派生的基本语法和用法。

2.技能目标:能够运用继承与派生编写C++程序,解决实际问题。

能够分析并修改现有程序中的继承与派生相关问题。

3.情感态度价值观目标:培养学生的编程思维,提高学生对C++程序设计的兴趣。

培养学生的团队协作能力,鼓励学生在课堂上积极互动、交流。

二、教学内容本章节的教学内容主要包括以下部分:1.继承与派生的概念及其作用。

2.继承与派生的基本语法和用法。

3.继承与派生在实际编程中的应用案例。

具体的教学大纲如下:1.第一课时:介绍继承与派生的概念及其作用。

2.第二课时:讲解继承与派生的基本语法和用法。

3.第三课时:通过案例分析,让学生掌握继承与派生在实际编程中的应用。

三、教学方法为了提高教学效果,本章节将采用以下教学方法:1.讲授法:讲解继承与派生的概念、语法和用法。

2.案例分析法:分析实际编程中继承与派生的应用,让学生更好地理解知识点。

3.实验法:让学生动手编写代码,巩固所学知识,提高实际编程能力。

四、教学资源为了支持本章节的教学,我们将准备以下教学资源:1.教材:《C++程序设计》等相关教材。

2.参考书:提供一些关于继承与派生的相关论文和书籍,供学生自主学习。

3.多媒体资料:制作PPT、视频等多媒体资料,帮助学生更好地理解知识点。

4.实验设备:提供计算机实验室,让学生能够动手编写代码,进行实验。

五、教学评估为了全面、客观地评估学生在学习C课程中继承与派生章节的学习成果,我们将采取以下评估方式:1.平时表现:通过课堂参与、提问、讨论等方式评估学生的学习态度和理解程度。

2.作业:布置与继承与派生相关的编程作业,评估学生对知识点的掌握和运用能力。

3.考试:安排一次期中考试,测试学生对继承与派生知识点的理解和运用能力。

C类的继承和派生ppt课件

C类的继承和派生ppt课件
this->x=x;this->y=y; } void Point::Show() {
cout<<"("<<x<<","<<y<<")"<<en dl; }
-
//Circle.h文件 #ifndef CIRCLE_H #define CIRCLE_H #include <iostream> #include "Point.h" using namespace std; class Circle:public Point { protected:
name=nam; sex=s; } ~Student( ){ } protected: int num; string name; char sex ; };
-
class Student1: public Student { public:
Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)
using namespace
std;
{ protected:
class Base
int j;
{ protected:
int i; public:
void F()
public: void Fun() { i=20; }
};
{
void main()
} };
{ Drived d;
}
-
4.5 派生类的构造函数和析构函数
如程序PointRect1所示:
-
4.4继承方式

最新《c 程序设计基础》第八章-继承和派生

最新《c  程序设计基础》第八章-继承和派生

❖ 方法二:面向对象?
▪ class circle 圆形
泛 ▪ class rectangle 矩形 化 ▪ class triangle 三角形 ? ▪ 基类: class shape
shape
• 色彩 color • 位置 (x, y)
circle rectangle
triangle
10
8.2.1 简单的继承和派生
class Shape: { public:
Shape(int x=0, int y=0, char c = 'R'); int GetX() const; void SetX( int x); int GetY() const; void SetY( int x); char GetColor() const; void SetColor(char c); protected: char m_color; int m_x; int m_y; };
17
class base {…… }; class deriver1:public base { …… }; class deriver2:public deriver1 {…… }
8.2.2 定义派生类
• 父类被称为子类的直 接基类
• 父类的父类或更高层 次的父类被称为这个 子类的间接基类
18
例2-图形类及其派生类的声明
的访问权限。 ❖ 每一个“继承方式”,只用于限制对紧随其后之基类的继承。
class derive : public b1 , private b2 { private:
int newInt; public:
void newFun(); private:
int max( int a, int b ); };

C++中的继承和派生详解

C++中的继承和派生详解

如图7.1所示,C++中有两种继承:单一继承和多重继承。 对于单一继承,派生类只能有一个基类;对于多重继承, 派生类可以有多个基类。
图7.1 类的单一继承和多重继承的UML结构图
在图7.1中,箭头指向基类。单一继承形成一个倒挂的 树。派生类继承了基类所有的数据成员和成员函数,程 序员也可以在派生类中添加新的数据成员和成员函数。 这样,基类定义了对象的一个集合,派生类通过增添新 的成员限制基类的定义,以便定义基类对象集合的一个 子集。 由此可见,从编码角度讲,派生类从基类中以较低代价 换来了大量的灵活性。一旦产生了可靠的基类,只需要 调试派生类中所做的修改即可。 C++派生类从父类中继承性质时,可使派生类扩展它们, 或者对其做些限制,也可改变或删除,甚至不作任何修 改。所有这些变化可归结为两类基本的面向对象技术。 第一种称为性质约束,即对基类的性质加以限制或删除。 第二种称为性质扩展,即增加派生类的性质。
冒号后“基类名(参数表)”称为成员初始化列表,参数 表给出所调用的基类构造函数所需要的实参。实参的值可 以来自“参数表0”,或由表达式给出。可以像Rectangle 那样,在类中直接定义为内联函数。下面是在类说明之外 定义的示范: Rectangle::Rectangle(int a, int b, int h, int w):Point(a,b) {H=h; W=w; cout<<"Rectangle..."<<endl;} “参数表0”有4个参数,基类Point的参数表是自己的2 个数据成员。 构造函数(包括析构函数)是不被继承的,所以一个派生 类只能调用它的直接基类的构造函数。当定义派生类的一 个对象时,首先调用基类的构造函数,对基类成员进行初 始化,然后执行派生类的构造函数,如果某个基类仍是一 个派生类,则这个过程递归进行。当该对象消失时,析构 函数的执行顺序和执行构造函数时的顺序正好相反。输出 结果也证实了这个结论。

08第八章继承与派生

08第八章继承与派生
一个基类成员在基类中的访问属性和在派生类中的访问属 性可能是不同的。私有基类的成员在私有派生类中的访问属 性见书中表8.2。 表8.2 私有基类在派生类中的访问属性
私有基类成员 私有成员 公有成员 保护成员来自在派生类中的访问 属性
不可访问 私有 私有
C++程序设计基础
8.4.3 保护成员和保护继承
由protected声明的成员称为“受保护的成员”,或简 称“保护成员”。
此外,在声明派生类时,一般还应当自己定义派生类的构 造函数和析构函数,因为构造函数和析构函数是不能从基类 继承的。
C++程序设计基础
实际上,并不是把基类的成员和派生类自己增加的成员简单 地加在一起就成为派生类。构造一个派生类包括以下3部分工 作:
(1)从基类接收成员。 派生类把基类全部的成员(不包括构造函数和析构函数)接收 过来,也就是说是没有选择的,不能选择接收其中一部分成员, 而舍弃另一部分成员。 要求我们根据派生类的需要慎重选择基类,使冗余量最小。 事实上,有些类是专门作为基类而设计的,在设计时充分考虑 到派生类的要求。 (2)调整从基类接收的成员。 接收基类成员是程序人员不能选择的,但是程序人员可以对 这些成员作某些调整。 (3)在声明派生类时增加的成员。 这部分内容是很重要的,它体现了派生类对基类功能的扩展。 要根据需要仔细考虑应当增加哪些成员,精心设计。
派生类中不可访问的成 员
在派生 类中 可以
可以
可以
不可以
在派生类 在下层公有派
外部
生类中
可以
可以
不可以
不可以
不可以
不可以
不可以
不可以
C++程序设计基础
8.5 派生类的构造函数

第八章 继承与派生

第八章 继承与派生

一般来说,公有派生是绝对主流。
公有派生与私有派生
1. 公有继承(public)。 公有继承的特点是基类的公有成员和保护成员作为派生 类的成员时,它们都保持原有的状态,而基类的私有成员仍 然是私有的。 2. 私有继承(private)。 私有继承的特点是基类的公有成员和保护成员作为派 生类的私有成员,并且不能被这个派生类的子类访问。
基类 派生类 基类 public public Protected protected private private private 不可见 private 派生 派生类 protected 基类 public protected private 派生类 public proteced
不可见
不可见
在派生类对象外 访问派生类对象 的基类成员
可直接访问 不可直接访问 不可直接访问 不可直接访问 不可直接访问 不可直接访问
公有派生
私有派生
(1)在公有继承时,派生类的对象可以访问基类中的公有成 员;派生类的成员函数可以访问基类中的公有成员和保护成员。 这里,一定要区分清楚派生类的对象和派生类中的成员函数对 基类的访问是不同的。 (2)在私有继承时,基类的成员只能由直接派生类访问,而 无法再往下继承。
继承与派生的概念 派生类的构造函数与析构函数 多重继承与派生类成员标识 虚基类 类层次中成员名的作用域 类层次中类转换规则 多重继承的应用例子 MFC基础类及其层次结构
继承与派生的概念
层次概念是计算机的重要概念。通过继承(inheritance)的 机制可对类(class)分层,提供类型/子类型的关系。C++通过 类派生(class derivation)的机制来支持继承。继承是类之间定 义的一种重要关系。定义类B时,自动得到类A的操作和数据属性, 使得程序员只需定义类A中所没有的新成分就可完成在类B的定义, 这样称类B继承了类A,类A派生了类B,A是基类(父类),B是 派生类(子类)。这种机制称为继承。 称已存在的用来派生新类的类为基类(base class) ,又称 为 父 类 。 由 已 存 在 的 类 派 生 出 的 新 类 称 为 派 生 类 ( derived class) ,又称为子类。派生类可以具有基类的特性,共享基类 的成员函数,使用基类的数据成员,还可以定义自己的新特性, 定义自己的数据成员和成员函数。基类和派生类的集合称作类继 承层次结构(hierarchy) 在C++语言中,一个派生类可以从一个基类派生,也可以从 多个基类派生。从一个基类派生的继承称为单继承;从多个基类 派生的继承称为多继承。下图反映了类之间继承和派生关系。

C++面向对象程序设计第8章 继承与派生

C++面向对象程序设计第8章 继承与派生
7
蚌埠学院计算机系
C++面向对象程序设计
class Studend1 可以看出,很多是重复的地方, 我们可以通过C++语言中的 { int num; //此行原来己有 继承机制,可以扩充和完善旧 char name[20]; //此行原来己有 的程序设计以适应新的需求。 char sex; //此行原来己有 这样不仅可以节省程序开发的 时间和资源,并且为未来程序 int age; 增添了新的资源。 char addr[20]; public: void display( ) ; //此行原来己有 {cout<<"num: "<<num<<endl; //此行原来己有 cout<<"name: "<<name<<endl;//此行原来己有 cout<<"sex: "<<sex<<endl; //此行原来己有 cout<<"age: "<<age<<endl; cout<<"address: "<<addr<<endl;} };
蚌埠学院计算机系
21
C++面向对象程序设计
【例8-3】定义类Point,然后定义类Point的派生类 Circle。 #include <iostream.h> class Point //定义基类,表示点 { private: int x; int y; public: void setPoint(int a, int b){ x=a; y=b; }; //设置坐标 int getX(){ return x; }; //取得X坐标 int getY(){ return y; }; //取得Y坐标 };
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第8章继承与派生8-1. 教学目的与要求1.理解继承的概念;2.掌握继承的实现方法;3.继承中常见问题的处理方法。

8-2. 主要内容及重点:类是C++中进行数据封装的逻辑单位。

继承是面向对象程序设计的一个重要特征之一,它允许在既有类的基础上创建新的类,新类可以从一个或多个既有类中继承操作和数据,而且可以重新定义或加进新的数据和操作,从而形成类的层次或等级。

既有类称为基类或父类,在它基础上建立的新类称为派生类、导出类或子类。

本章的重点是派生类的定义和使用、创建派生类对象时构造函数的调用顺序、多重继承中的冲突及其消除方法以及作用域运算符的几种使用方法等。

本章的难点是基类的初始化、多重继承中的冲突以及虚基类等。

8-3. 第8章继承-课件3-4. 8-4. 第8章继承-复习总结继承是面向对象程序设计方法的基本特性之一,继承可以提高软件的重要性。

本章主要介绍了C++中的继承性的实现方法以及在继承性常见问题的处理方法。

包括基类的初始化、访问类型的调整、冲突及其消除方法、成员覆盖、赋值兼容性以及虚基类等。

类的派生包括三种类型:私有派生、保护派生、公有派生。

利用构造函数的初始化成员列表,可以在派生类中对基类成员进行初始化。

在继承层次关系中要避免冲突的产生,通常是采用指定作用域和定义虚基类这两种方法来解决问题。

8-5. 第8章继承-练习8-5-1.思考题:1).派生类有几种方式,每种方式中派生类对基类成员的继承如何?2). 在创建派生类对象时,构造函数的执行次序是怎样的?析构函数的执行次序是怎样的?3). 派生类对象如何对基类中的成员进行初始化?4). 在多重继承中,在什么情况下会产生冲突?如何消除冲突? 5). 列举我们已学习的作用域运算符“::”的所有用途。

6). 属于不同类的对象在什么情况下可以互相赋值? 7).什么叫虚基类?为什么要引进虚基类?8-5-2.练习题:课后练习题见练习单元。

第8章 继承与派生继承是面向对象程序设计的一个重要特征之一,它允许在既有类的基础上创建新的类,新类可以从一个或多个既有类中继承操作和数据,而且可以重新定义或加进新的数据和操作,从而形成类的层次或等级。

既有类称为基类或父类,在它基础上建立的新类称为派生类、导出类或子类。

8 .5 虚基类8 .5.1 虚基类的概念对于直接继承,一个基类只能被派生类继承一次;对于间接继承,一个基类可以被派生类继承多次。

如图所示的继承结构中,基类A 在类D 中会产生两个副本。

这时如果在D 类中使用从A 类继承的成员时,如果不指定其作用域,会出现同名冲突。

虚基类的基本思想是:将一个基类声明为虚基类时,不管它在派生类中被继承多少次,该基类中的成员在该派生类中始终只有一个副本,如图。

虚基类是通过关键字virtual 实现的,定义虚基类的格式为:class <派生类>:virtual <access><基类名>《,---,virtual<accesss<基类名>>》 { --- } ; 或图 虚基类的类层次class<派生类名>:<access>virtual <基类名>《,---,<access>virtual<基类名>》{---} ;例1:使用虚基类,使派生类中只有基类一个副本。

# include <iostream.h>class CFurniture{ protected:int weight ;public:CFurniture( ){ }void SetWeight (int i ) { weight=i ;}int GetWeight ( ) {return weight ;}};{cout<<”sleeping ---\n’;}class CBed:virtual public CFurniture //A定义虚基类{public :CBed ( ){ }void sleep ( )} ;class CSofa:virtual public CFurniture //B 定义虚基类{ public:CSofa ( ) { }void WatchTV(){cout<<”Watch TV . \n “;}} ;class CSleepSofa :public CBad ,public Csofa{public :CSleepSofa ( ){ }void FoldOut ( ){cout<<”Fold out the sofa 。

\n ”;}};void main (){CSleepSofa ss ;ss.SetWeight (20) ;//Ccout<<ss.GetWeight( )<<’\n’;//D}执行结果:20例//program 8-6.cpp p269#include <iostream.h>class A {public:int i;void showa(){cout<<"i="<<i<<endl;}};class B: virtual public A //对类A进行了虚拟继承{public:int j;};class C: virtual public A //对类A进行了虚拟继承{public:int k;};class D : public B, public C//派生类D的二基类B、C具有共同的基类A,但采用了虚拟继承//从而使类D的对象中只包含着类A的1个实例{public:int n;void showall(){cout<<"i,j,k,n="<<i<< “ ,”<<j<< “ ,”<<k<< “ ,”<<n<<endl;} };void main() {D Dobj; //说明D类对象Dobj.i=11;//若非虚拟继承时会出错!// -- 因为“D::a”具有二义性Dobj.j=22;Dobj.k=33;Dobj.n =44;Dobj.showa();//若非虚拟继承时会出错!// -- 因为“D::showa”具有二义性Dobj.showall();}程序执行后的显示结果如下:/*i=11i,j,k,n=11 ,22 ,33 ,44Press any key to continue*/8 .5.2 虚基类的初始化虚基类的初始化与一般的多重继承的初始化在语法上是一致的,但构造函数的调用次序有不同。

1.虚基类的构造函数在非虚基类的构造函数之前调用。

如下例的B 行2.若同一层次中包含多个虚基类,这些虚基类的构造函数按它们的说明次序调用。

3.若虚基类由非虚基类派生而来,则仍然先调用基类的构造函数,再调用派生类的构造函数,如下例的A 行。

4.对图的类层次结构,由于此时虚基类A 在类D 中只有一个副本,因此在创建D 的对象时,无法确定是通过类B 还是通过类C 调用A 的构造函数,为了解决这个矛盾,C++规定在这种情况下可以在类D 中,直接调用类A 的构造函数。

即在D 类的构造函数的初始化成员列表中,不仅要调用类B 的构造函数,还必须调用类A 的构造函数而且是最先调用。

因为在类D 只有A 的一个版本,所以调用类B 和类C的构造函数时不再重复调用类A 的构造函数了,即 类A 的构造函数只运行一次。

下面通过一个例子来说明这一个问题。

例1 虚基类的构造函数的调用次序 # include <iostream.h> class CBase1 {public :CBase1 ( ){cout<<”This is CBase1 class! \ n “ ;} }; class CBase2 {public :CBase2 ( ) {cout<<”This is CBase2 class ! \n “ ;} };class CDerive1:public CBase2 ,virtual public CBase1 //A {public :CDerive1( ){cout<<”This is CDerive1 class ! \n “ ;}};class CDerive2:public CBase2 ,virtual public CBase1 //A {public :CDerive2 ( ){cout<<”This is CDerive2 class ! \n “ ;} };class CTop :public CDerive1 ,virtual public CDerive2 //B {public :CTop ( ){cout<<”This is CTop class ! \n “ ;} };图 虚基类的类层次void main ( ){ CTop topObj ; } 执行结果: This is CBase1 class ! This is CBase2 class ! This is CDerive2 class ! This is CBase2 class ! This is CDerive1 class ! This is CTop class !例2 初始化虚基类成员 # include <iotream.h> class CBase{int x ,y ; public :CBase ( int a , int b ) {x=a , y=b ;}show ( ){cout<<x<<’\t ’<<y<<endl ;}};class CDerive1:virtual public CBase //A 声明CBase 为虚基类 {public :CDerive1( ):CBase(2,3) { } };class CDerive2:virtual public CBase //B 声明CBase 为虚基类 public :CDerive2 ( ):CBase (4 ,5) { } } ;class CTop :public CDerive1,public CDerive2 {public :CTop ( ):CBase (6 , 7 ) //C 直接调用虚基类CBase 的构造函数, { } //如果A 、B 行没有声明CBase 为虚基类,则不可这样使用。

相关文档
最新文档