面向对象程序设计 QQ群:343072849 Object-Oriented Programming 汽车学院.

Slides:



Advertisements
Similar presentations
第3-2章 类与 对象 Java类的特性 教学内容: 类的私有成员与公共成员 方法的重载 构造方法 实例成员与静态成员 重点: 重载 难点:
Advertisements

移动应用软件开发技术 第二讲:C++编程基础
第四章 继承与派生 Chapter 4 Inheritance and Derivation
第6章 多态性与虚函数.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
第八章 类和对象.
C++语言程序设计教程 第7章 类与对象 第7章 类与对象.
内容提要 对象的生命周期 构造函数 析构函数 拷贝构造函数. 常宝宝 北京大学计算机科学与技术系
第四章 在 C# 中实现 OOP 概念.
4.1 概述 4.2 类与对象的实现 4.3 对象的初始化和析构 4.4 类的包含 4.5 类模板
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
教材 《C++程序设计》.谭浩强. 清华大学出版社 王雪晶
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第三章 C#面向对象初级编程 面向对象得程序设计越来越受到编程人员的喜爱。类和对象是面向对象程序设计中的重要概念。封装性、继承性和多态性是面向对象的特点,本章旨在全面说明C#编写面向对象程序设计的方法。
第六章 继承性和派生类 胡昊 南京大学计算机系软件所.
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
Object-Oriented Programming:
第3章 继承和派生.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
C++语言程序设计教程 第7章 类与对象 第7章 类与对象.
第四章 小技巧.
类类型 C++支持的内置类型和操作,如 int i=10; i=i%6; i=i+4;
第9讲 Java的继承与多态(一) 类的继承 子类的创建 方法覆盖.
Php class 組員: 賴羿陵 林昱廷 莊正暉 張雅晴
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
C++面向对象程序设计 谭浩强编著 授课教师:姬广永 QQ: 学习网站:
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
第12讲 多继承与虚基类 多继承 虚基类.
C++语言程序设计 C++语言程序设计 第五章 函数 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
C++复习2----类与对象.
物件導向程式設計 CH2.
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
Inheritance -II.
第三章 数据抽象.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++程式設計入門 變數與運算子 作者:黃建庭.
C++大学基础教程 第10章 运算符重载 北京科技大学 2019/5/7 北京科技大学.
面向对象技术 练习 ffh.
C++程序设计基础 主讲人:谢昕 华东交通大学信息工程学院 第十~十二讲 多态性和虚函数 2005年春季学期.
本节内容 引用类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
第1章 C++面向对象程序设计要点 1.1 函数和函数参数 1.2 输入输出   1.3 类 1.4 抽象类型和模板.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
#include <iostream.h>
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
第 5 章 继承、多态和虚函数 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
C++语言程序设计 第十章 C++标准模板库 成都信息工程学院计算机系.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第三章 高级函数特性.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++语言程序设计(第4版) 第七章 继承与派生 数学与统计科学学院 胡凤珠.
變數與資料型態  綠園.
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
安排座位.
第十二章 C与C C转入C++时不需改变的内容 12.2 C转入C++的一些与类无关的 新特性
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

面向对象程序设计 QQ群:343072849 Object-Oriented Programming 汽车学院

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例 Object-Oriented Programming 汽车学院

4.1 派生类的概念 4.1.1 为什么要使用继承 4.1.2 派生类的声明 4.1.3 派生类的构成 4.1.1 为什么要使用继承 4.1.2 派生类的声明 4.1.3 派生类的构成 4.1.4 基类成员在派生类中的访问属性 4.1.5 派生类对基类成员的访问规则 Object-Oriented Programming 汽车学院

4.1.1 为什么要使用继承 继承 在已有类的基础上建立一个新类的过程称为继承 被继承的已有类称为基类(父类) 派生 4.1.1 为什么要使用继承 继承 在已有类的基础上建立一个新类的过程称为继承 被继承的已有类称为基类(父类) 派生 在已有类的基础上新增自己的特性(属性与行为)而产生新类的过程称为派生 派生出的新类称为派生类(子类) 继承与派生的目的:实现代码的重用与扩充 Object-Oriented Programming 汽车学院

单继承 派生类只从一个基类派生 Object-Oriented Programming 汽车学院

多重继承 一个派生类有两个或多个基类 Object-Oriented Programming 汽车学院

多级派生(多层派生) 派生类又作为基类,继续派生新的类 Object-Oriented Programming 汽车学院

4.1.2派生类的声明 class 派生类名:[继承方式] 基类名 { //派生类新增的数据成员和成员函数 //定义一个基类 }; 继承方式:规定了如何访问从基类继承的成员,可以是private,protected,public三种方式. //定义一个基类 class Person { public: void print() { // … …} protected: string name; int age; char sex; }; //定义一个派生类 class Employee:public Person { public: void print1() { ……….} private: string department; float salary; }; Object-Oriented Programming 汽车学院

由类Person继承出类Employee有三种继承方式 (1) 公有继承 class employee:public person { //… }; (2) 私有继承 class employee:private person (3) 保护继承 class employee:protected person Object-Oriented Programming 汽车学院

4.1.3派生类的构成 Person类 Employee类 string name; string name; int age; 继承与派生的目的:实现代码的重用与扩充 4.1.3派生类的构成 派生类除了可以从基类继承成员外,还可以增加自己的数据成员和成员函数.这些新增的成员正是派生类不同于基类的关键所在,是派生类对基类的发展. Person类 string name; int age; char sex; void print(); Employee类 string name; int age; char sex; void print() 继承 string department; float salary; void print1(); 新增(发展)

C++继承中,派生类把基类的全部成员(构造函数与析构函数除外)接收过来. (2)调整从基类接收来的成员 (3)在派生类中增加新成员. 构造一个派生类一般过程: (1)派生类从基类接收成员 C++继承中,派生类把基类的全部成员(构造函数与析构函数除外)接收过来. (2)调整从基类接收来的成员 (3)在派生类中增加新成员. Object-Oriented Programming 汽车学院

4.1.4基类成员在派生类中的访问属性 派生类继承基类中全体成员(除了构造函数与析构函数).这些成员的访问属性在派生过程中可以调整. 从基类继承来的成员在派生类的访问属性是由继承方式控制. class 派生类名:[继承方式] 基类名 { // ……. } 不同的继承方式,导致不同访问属性的基类成员在派生类的访问属性有所不同. 用公有继承方式建立的派生类称为公有派生类 用私有继承方式建立的派生类称为私有派生类 用保护继承方式建立的派生类称为保护派生类 Object-Oriented Programming 汽车学院

表:基类成员在派生类中的访问属性 基类中的成员 在公有派生类中的访问属性 在私有派生类中的访问属性 在保护派生类中的访问属性 私有成员 公有成员 保护成员 不可直接访问 公有 保护 私有 Object-Oriented Programming 汽车学院

4.1.5 派生类对基类成员的访问规则 类的继承方式有 public(公有继承) protected(保护继承) private(私有继承) 不同的继承方式导致原来具有不同访问属性的基类成员在派生类中的访问属性不同. 派生类对基类成员的访问形式有以下两种: (1)内部访问,派生类的新增成员函数对基类继承的成员的访问 (2)对象访问,在派生类的外部,以派生类的对象对基类继承来的成员的访问. Object-Oriented Programming 汽车学院

表:派生类对基类成员的访问规则 基类中的成员 私有成员 公有成员 保护成员 私有继承 访问方式 内部访问 不可访问 可访问 对象访问 公有继承 保护继承 Object-Oriented Programming 汽车学院

1.私有继承的访问规则 基类中的private成员,既不能被派生类的对象访问, 也不能被派生类的新增成员函数访问(内部访问). 基类成员 public成员 protected成员 内部访问 对象访问   不可访问 可访问 基类中的private成员,既不能被派生类的对象访问, 也不能被派生类的新增成员函数访问(内部访问). Object-Oriented Programming 汽车学院

int main() { Derived obj; obj.setx(10); obj.showx(); obj.setxy(20,30); P142:例4.1 int main() { Derived obj; obj.setx(10); obj.showx(); obj.setxy(20,30); obj.showxy(); return 0; } class Base { public: void setx(int n) { x=n; } void showx() { cout <<x<<endl; } private: int x; }; class Derived: private Base { public: void setxy(int n,int m) { setx(n); y=m; } void showxy() { cout <<x; cout<<y<<endl; } int y; ╳ ╳ #include <iostream> using namespace std; class Base { public: void setx(int n) { x=n; } void showx() { cout <<x<<endl; } private: int x; }; class Derived: private Base { public: void setxy(int n,int m) { setx(n); y=m; } void showxy() { //cout <<x; //派生类内不能直接访问基类的私有成员 showx();//派生类内可以通过新增的成员函数访问基类公有成员函数 cout<<y<<endl; } int y; int main() Derived obj; //obj.setx(10); //私有继承方式不能通过派生类对象访问基类公有成员函数 //obj.showx(); obj.setxy(20,30); obj.showxy(); return 0; } ╳

2.公有继承的访问规则 基类成员 private成员 public成员 protected成员 内部访问 对象访问 不可访问 可访问   不可访问 可访问 Object-Oriented Programming 汽车学院

{ cout <<x << y<< endl; } private: int x; protected: class Base { public: void setxy(int m,int n) { x=m; y=n; } void showxy() { cout <<x << y<< endl; } private: int x; protected: int y; }; class Derived: public Base { public: void setxyz(int m,int n,int l) { setxy(m,n); z=l; } void showxyz() { cout <<x; cout<<y; cout <<z; } int z; int main() { Derived obj; obj.setxyz(30,40,50); obj.showxy(); obj.y=60; obj.showxyz(); return 0; } ╳ #include <iostream> using namespace std; class Base { public: void setxy(int m,int n) { x=m; y=n; } void showxy() { cout <<x << y<< endl; } private: int x; protected: int y; }; class Derived: public Base { public: void setxyz(int m,int n,int l) { setxy(m,n); z=l; } void showxyz() { //cout <<x;//公有继承方式派生类内不能通过新增成员函数访问基类私有成员 cout<<y; //公有继承方式派生类内可以通过新增成员函数访问基类保护成员 cout <<z; } int z; int main() { Derived obj; obj.setxyz(30,40,50); obj.showxy(); //obj.y=60;//公有继承不能通过派生类对象访问基类保护成员 obj.showxyz(); return 0; ╳ P145:例4.3

3.保护继承的访问规则 基类成员 private成员 public成员 protected成员 内部访问 对象访问 不可访问 可访问   不可访问 可访问 Object-Oriented Programming 汽车学院

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例 Object-Oriented Programming 汽车学院

4.2派生类的构造函数与析构函数 派生类继承了基类的成员,实现了代码的重用,引入继承更主要的目的是代码的扩充.所以,只有在派生类中加入新成员,派生才更有实际意义. 派生类不能继承基类的构造函数,在派生类中对新增成员的初始化,加入派生类的构造函数,基类继承下来的成员初始化由基类构造函数完成. 同样,当撤销对象时,也需要加入派生类的析构函数来执行清理工作. Object-Oriented Programming 汽车学院

4.2 派生类的构造函数和析构函数 4.2.1 派生类构造函数和析构函数的执行顺序 4.2.2 派生类构造函数和析构函数的构造规则 4.2.1 派生类构造函数和析构函数的执行顺序 4.2.2 派生类构造函数和析构函数的构造规则 Object-Oriented Programming 汽车学院

4.2.1 派生类构造函数和析构函数的执行顺序 当创建派生类对象时,首先执行基类的构造函数,随后再执行派生类的构造函数;当撤消派生类的对象时,则先执行派生类的析构函数,随后再执行基类的析构函数. Object-Oriented Programming 汽车学院

P150:例4.5 class Base { public: Base(){ cout<<"Constructing base class\n"; } ~Base(){ cout<<"Destructing base class\n"; } }; class Derive:public Base { public: Derive(){cout<<"Constructing derived class\n";} ~Derive(){cout<<"Destructing derived class\n";} int main() { Derive op; return 0; } Constructing base class Constructing derived class Destructing derived class Destructing base class

4.2.2 派生类构造函数和析构函数的构造规则 1.简单派生类的构造函数 当基类的构造函数没有参数,或没有显式定义构造函数时,派生类可以不向基类传递参数,甚至可以不定义构造函数. 当基类含有带参数的构造函数时,由于派生类不能继承基类的构造函数与析构函数,此时,派生类必须定义构造函数,以提供把参数传递给基类构造函数的途径. Object-Oriented Programming 汽车学院

其中:基类构造函数的参数,通常来源于派生类构造函数的参数总表.也可用常数值. 在C++中派生类构造函数的一般形式为: 派生类名(参数总表):基类名(参数表) { //…… 派生类新增数据成员的初始化语句 } 其中:基类构造函数的参数,通常来源于派生类构造函数的参数总表.也可用常数值. Object-Oriented Programming 汽车学院

Student(int number1,string name1,float score1) { number=number1; P151:例4.6 class Student { public: Student(int number1,string name1,float score1) { number=number1; name=name1; score=score1; } void print() { cout << "number:"<<number<<endl; cout << "name:"<<name<<endl; cout << "score:"<<score<<endl; protected: int number; string name; float score; };

class UStudent:public Student { public: UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,score1) { major=major1; } void print1() { print(); cout << "major:"<<major<<endl; } private: string major; }; int main() { UStudent stu(201,"胡达",100,"自动化"); stu.print1(); return 0; } #include <iostream> using namespace std; #include<string> class Student { public: Student(int number1,string name1,float score1) { number=number1; name=name1; score=score1; } void print() { cout << "number:"<<number<<endl; cout << "name:" << name << endl; cout << "score:"<<score<<endl; protected: int number; string name; float score; }; class UStudent:public Student { public: UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,score1) { major=major1; } void print1() { print(); cout << "major:"<<major<<endl; private: string major; int main() UStudent stu(201,"胡达",100,"自动化"); stu.print1(); return 0;

说明: (1)可以将派生类的构造函数定义在类的外部,类体内只写该函数的声明. 在类中声明派生类的构造函数时,不包括基类构造函数名及其参数表.只在类外定义构造函数时才将它列出来. class UStudent:public Student { public: UStudent(int number1,string name1,float score1,string major1); void print1() { print(); cout <<"major:"<<major<<endl; } private: string major; }; UStudent::UStudent(int number1,string name1,float score1,string major1):Student(number1,name1,major1) major=major1;

(2)如果基类使用默认构造函数或不带参数的构造函数,则在派生类中定义构造函时可以去掉”:基类构造函数名(参数表)”,此时若派生类不需要构造函数,则可不定义派生类的构造函数. 派生类名(参数总表) { //…… 派生类新增数据成员的初始化语句 } Object-Oriented Programming 汽车学院

(3)当基类的构造函数不带参数时,派生类不一定需要定义构造函数,然而当基类的构造函数哪怕只带一个参数,它所有的派生类都必须定义构造函数,甚至所定义的派生类函数可能为空,仅仅起到参数传递作用. Object-Oriented Programming 汽车学院

2.派生类的析构函数 在派生类中可以根据需要定义自己的析构函数,用于对派生类中新增加的成员进行清理工作,基类的清理工作仍然由基类的析构函数负责. 析构函数是无参的函数. Object-Oriented Programming 汽车学院

3.含有对象成员 (子对象)的派生类的构造函数 当派生类中含有内嵌的对象成员(子对象)时,其构造函数的一般形式为: 派生类名(参数总表):基类名(参数表0),对象成员名1(参数表1),……,对象成员名n(参数表n) { // 派生类新增数据成员的初始化语句 } 在定义派生类对象时,构造函数执行顺序 (1)调用基类的构造函数,对基类数据成员初始化 (2)调用内嵌对象成员的构造函数(内嵌对象成员有多个,执行顺序与在类中的声明顺序一致),对内嵌对象成员的数据成员初始化 (3)调用派生类的构造函数,对派生类数据成员初始化 撤消对象时,析构函数的调用顺序与构造函数正好相反 Object-Oriented Programming 汽车学院

cout << "Constructing base class\n"; } ~Base() class Base { public: Base(int i) { x=i; cout << "Constructing base class\n"; } ~Base() { cout << "Destructing base class\n"; } void show() { cout << x<<endl; } private: int x; }; class Derived:public Base {public: Derived(int i):Base(i),d(i) { cout << "Constructing derived class\n";} ~Derived() { cout << "Destructing derived class\n"; } Base d; int main() { Derived obj(5); obj.show(); return 0; } Constructing base class Constructing derived class 5 Destructing derived class Destructing base class #include <iostream> using namespace std; class Base { public: Base(int i) { x=i; cout << "Constructing base class\n"; } ~Base() { cout << "Destructing base class\n"; } void show() { cout << x<<endl; } private: int x; }; class Derived:public Base {public: Derived(int i):Base(i),d(i) { cout << "Constructing derived class\n";} ~Derived() { cout << "Destructing derived class\n"; } Base d; int main() { Derived obj(5); obj.show(); return 0; P155:例4.8

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例 Object-Oriented Programming 汽车学院

4.3 调整基类成员在派生类中的访问属性的其他方法 4.3.1 同名成员 派生类中定义了与基类成员同名的成员,则派生类成员覆盖了基类的同名成员,在派生类中使用这个名字意味着访问在派生类中重新说明的成员。 为了能够使用基类的同名成员,必须采用如下形式: 基类名::成员名 Object-Oriented Programming 汽车学院

int main() { B b(10,20); b.show(); return 0; } x=10 y=20 class A { public: A(int x1) { x=x1; } void print() { cout << "x="<<x<<endl;; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } { cout << "y="<<y<<endl; } void show() print(); A::print(); } int y; int main() { B b(10,20); b.show(); return 0; } x=10 y=20 #include <iostream> using namespace std; class A { public: A(int x1) { x=x1; } void print() { cout << "x="<<x<<endl;; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } { cout << "y="<<y<<endl; } void show() print(); A::print(); } int y; int main() B b(10,20); b.show(); return 0;

在面向对象程序设计中,若要在派生类中对基类继承过来的某些函数功能进行扩充和改造,都可以采用这样覆盖的方法实现。 说明: 在面向对象程序设计中,若要在派生类中对基类继承过来的某些函数功能进行扩充和改造,都可以采用这样覆盖的方法实现。 Object-Oriented Programming 汽车学院

4.3.2 访问声明 对于公有继承,基类的公有成员函数也就是派生类的公有成员函数,在外界可以用派生类的对象直接调用基类的公有成员函数。但对于私有继承,基类的公有成员函数便成了派生类的私有成员函数,外界无法用派生类的对象直接调用基类的公有成员函数,只能通过调用派生类的成员函数间接调用基类公有成员函数。 Object-Oriented Programming 汽车学院

例4.11 访问声明引例。 int main() class A { { public: A(int x1) B b(10,20); b.print2(); return 0; } class A { public: A(int x1) { x=x1; } void print() { cout << "x="<<x; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } void print2() { print(); } int y; X=10 #include <iostream> using namespace std; class A { public: A(int x1) { x=x1; } void print() { cout << "x="<<x<<endl;; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } void print2() { print(); //cout << "y="<<y<<endl; } int y; int main() B b(10,20); b.print2(); return 0; 通过派生类B的函数print2调用基类A的函数print

访问声明 访问声明的方法是把基类的保护成员或公有成员直接写至私有派生类定义式中的同名段中,同时给成员名前加以基类名和作用域标识符::。利用这种方法,该成员就成为派生类的保护成员或公有成员了。 Object-Oriented Programming 汽车学院

例4.12 访问声明的应用。 class A { public: A(int x1) int main() { x=x1; } { void print() { cout << "x="<<x; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } A::print; int y; int main() { B b(10,20); b.print(); return 0; } X=10 #include <iostream> using namespace std; class A { public: A(int x1) { x=x1; } void print() { cout << "x="<<x<<endl;; } private: int x; }; class B:private A { public: B(int x1,int y1):A(x1) { y=y1; } A::print; int y; int main() { B b(10,20); b.print(); return 0; } 访问声明:把基类公有成员函数print调整为私有派生类的公有成员函数

4.3.2 访问声明 说明1:数据成员也可以使用访问声明。 class A{ private: …… public: int x2; } class B: private A { B (int x1, int y1): A(x1) { y = y1;} A:: x2; //把基类中的x2调整为派生类的公有成员 Object-Oriented Programming 汽车学院

4.3.2 访问声明 A::print; 说明2:访问声明中只含有不带类型和参数的函数名或变量名。下列哪些是对的: 写成: void A::print; A:: print( ); void A:: print( ); Object-Oriented Programming 汽车学院

4.3.2 访问声明 说明3:访问声明不能改变成员原来在基类中的成员性质。即访问声明只能把原基类的保护成员和公有成员分别调整为派生类的保护成员和公有成员.不能对基类的私有成员使用访问声明. Object-Oriented Programming 汽车学院

4.3.2 访问声明 class B: private A { class A { public: public: A::x1; //A::x2;A::x3;对吗? protected: A::x2; //A::x1; A::x3;对吗? private: //A::x1; A::x2; A::x3;对吗? }; class A { public: int x1; protected: int x2; private: int x3; }; Object-Oriented Programming 汽车学院

说明4:对于基类中的重载函数名, 访问声明将对基类中的所有同名函数起作用。这意味着对于重载函数使用访问声明要慎重。 4.3.2 访问声明 说明4:对于基类中的重载函数名, 访问声明将对基类中的所有同名函数起作用。这意味着对于重载函数使用访问声明要慎重。 Object-Oriented Programming 汽车学院

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例 Object-Oriented Programming 汽车学院

4.4 多重继承 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 Object-Oriented Programming 汽车学院

4.4 多重继承 当一个派生类有两个或以上的基类时,这种派生方法就叫做多重继承或多重派生 派生类只有一个基类,称为单继承 Object-Oriented Programming 汽车学院

class 派生类名:继承方式1 基类名1, …… ,继承方式n 基类名n { //…… 派生类新增的成员 } 4.4.1 多重继承派生类的声明 class 派生类名:继承方式1 基类名1, …… ,继承方式n 基类名n { //…… 派生类新增的成员 } Object-Oriented Programming 汽车学院

多重继承中,三种继承方式对基类成员在派生类中的访问属性规则与单继承相同。 多重继承访问属性规则 多重继承中,三种继承方式对基类成员在派生类中的访问属性规则与单继承相同。 Object-Oriented Programming 汽车学院

【例4.13】多重继承情况下派生类的访问特性。 #include <iostream> using namespace std; class X{ public: void setX(int x) { a=x; } void showX() { cout << "a=" << a << endl; } private: int a; }; class Y{ void setY(int x) { b=x; } void showY() { cout << "b=" << b << endl; } int b; class Z: public X, private Y{ public: void setZ(int x, int y) { c=x; setY(y); } void showZ() { showY(); cout << "c=" << c << endl; } private: int c; }; int main() { Z obj; obj.setX(3); obj.showX(); obj.setY(4); //ERROR! 成员函数setY在Z中已成为私有成员 obj.showY(); //ERROR! 成员函数showY在Z中为私有成员 obj.setZ(6, 8); obj.showZ(); return 0; } Object-Oriented Programming 汽车学院

class Z: X, public Y {  } 说明1:缺省的继承方式是private Object-Oriented Programming 汽车学院

说明2: 对基类成员的访问必须是无二义的. class X{ public: int f(); }; class Y{ int g(); class Z : public X,public Y{ public: int main() { Z obj; //obj.f(); obj.X::f(); } X Y Z #include <iostream> using namespace std; class X{ public: int f(); }; class Y{ int g(); class Z : public X,public Y{ public: int X::f() { cout<<"X类函数f():"; return 1; } int Y::f() cout<<"Y类函数f():"; return 2; int Z::g() cout<<"Z类函数g():"; return 3; int main() Z obj; //cout<<obj.f()<<endl; //二义性错误,不知调用的是类X的f(),还是类Y的f() cout<<obj.X::f()<<endl; //调用的是类X的f() cout<<obj.Y::f()<<endl;; //调用的是类Y的f() return 0; Object-Oriented Programming 汽车学院

4.4 多重继承 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 Object-Oriented Programming 汽车学院

4.4.2 多重继承派生类的构造函数与析构函数 多重继承下派生类构造函数的定义形式与单继承派生类的构造函数相类似.只是n个基类的构造函数之间用逗号分隔. 派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),……,基类名n(参数表n) { // …… 派生类新增成员的初始化语句 } Object-Oriented Programming 汽车学院

(1)先执行基类的构造函数(同一层次的各个基类的执行顺序,取决于声明派生类时指定的各个基类的顺序) 多重继承的构造函数执行顺序: (1)先执行基类的构造函数(同一层次的各个基类的执行顺序,取决于声明派生类时指定的各个基类的顺序) (2)执行对象成员的构造函数(含有多个内嵌的对象成员,执行顺序由它们在类中声明的顺序确定) (3)最后执行派生类构造函数 Object-Oriented Programming 汽车学院

4.4 多重继承 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 4.4.1 多重继承派生类的声明 4.4.2 多重继承派生类的构造函数和析构函数 4.4.3 虚基类 Object-Oriented Programming 汽车学院

当一个类的多个直接基类是从另一个共同基类派生而来时,这些直接基类中从上一级基类继承来的成员就有相同的名称。 4.4.3 虚基类 问题1. 为什么要引入虚基类 当一个类的多个直接基类是从另一个共同基类派生而来时,这些直接基类中从上一级基类继承来的成员就有相同的名称。 那么在派生类对象中,就存在如何对这些具有相同名称的成员进行分辨的问题。 Object-Oriented Programming 汽车学院

4.4.3 虚基类 【例4.15】虚基类的引例。P170 #include <iostream> using namespace std; class Base { public: Base(){ a=5; cout<<"Base a="<<a<<endl; } protected: int a; }; class Base1:public Base{ Base1() { a=a+10; cout<<"Base1 a="<<a<<endl; } class Base2:public Base{ Base2() {a=a+20; cout<<"Base2 a="<<a<<endl;} Object-Oriented Programming 汽车学院

4.4.3 虚基类 base 程序运行结果如下: base a=5 base1 a=15 base2 a=25 base1 base2 class Derived:public Base1,public Base2{ public: int d; Derived() { cout<<"Base1::a="<<Base1::a<<endl; cout<<"Base2::a="<<Base2::a<<endl; //cout<<"derived a="<<a <<endl; //二义性 } }; main() { Derived obj; return 0; } base1 base2 base derived 图4-3 非虚基类的类层次图 程序运行结果如下: base a=5 base1 a=15 base2 a=25 base1::a=15 base2::a=25 #include <iostream> using namespace std; class Base { public: Base(){ a=5; cout<<"Base a="<<a<<endl; } protected: int a; }; class Base1:public Base{ Base1() { a=a+10; cout<<"Base1 a="<<a<<endl; } class Base2:public Base{ Base2() {a=a+20; cout<<"Base2 a="<<a<<endl;} class Derived:public Base1,public Base2{ int d; Derived() { cout<<"Base1::a="<<Base1::a<<endl; cout<<"Base2::a="<<Base2::a<<endl; //cout<<"derived a="<<a <<endl; //二义性 } main() { Derived obj; return 0; Object-Oriented Programming 汽车学院

4.4.3 虚基类 问题2. 虚基类的概念 如果在上例中公共基类base只存在一个拷贝,那么对a的访问就不存在二义性。为了达到这一目的,可将base说明为虚基类。 虚基类的声明在派生类的声明过程进行, 其语法形式如下: class 派生类名:virtual 继承方式 基类名{ //… } Object-Oriented Programming 汽车学院

4.4.3 虚基类 【例4.16】虚基类的使用。P173 class Base { public: #include <iostream> using namespace std; class Base { public: Base( ){ a=5; cout<<"Base a="<<a<<endl;} protected: int a; }; class Base1: virtual public Base{ Base1( ){ a=a+10; cout<<"Base1 a="<<a<<endl;} class Base2: virtual public Base{ Base2( ){ a=a+20; cout<<"Base2 a="<<a<<endl;} Object-Oriented Programming 汽车学院

4.4.3 虚基类 class Derived: public Base1, public Base2{ public: cout<<"Derived a="<<a<<endl; } }; int main( ) Derived obj; return 0; 程序运行结果如下: base a=5 base1 a=15 base2 a=35 derived a=35 #include <iostream> using namespace std; class Base { public: Base(){ a=5; cout<<"Base a="<<a<<endl; } protected: int a; }; class Base1:virtual public Base{ Base1() { a=a+10; cout<<"Base1 a="<<a<<endl; } class Base2:virtual public Base{ Base2() {a=a+20; cout<<"Base2 a="<<a<<endl;} class Derived:public Base1,public Base2{ int d; Derived() { cout<<"Base1::a="<<Base1::a<<endl; cout<<"Base2::a="<<Base2::a<<endl; cout<<"derived a="<<a <<endl; } main() { Derived obj; return 0; Object-Oriented Programming 汽车学院

4.4.3 虚基类 base1 base2 derived 图4-5 虚基类的类层次图   derived 图4-5 虚基类的类层次图 Object-Oriented Programming 汽车学院

4.4.3 虚基类 问题3. 虚基类的初始化 在使用虚基类机制时应该注意以下几点: (1) 如果在虚基类中定义有带形参的构造函数,并且没有定义缺省形式的构造函数,则整个继承结构中,所有直接或间接的派生类都必须在构造函数的成员初始化表中列出对虚基类构造函数的调用,以初始化在虚基类中定义的数据成员; Object-Oriented Programming 汽车学院

4.4.3 虚基类 2)建立一个对象时,如果这个对象中含有从虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。该派生类的其他基类对虚基类构造函数的调用都自动被忽略; 3)若同一层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数; Object-Oriented Programming 汽车学院

4.4.3 虚基类 (4) 对于多个虚基类,构造函数的执行顺序仍然是先左后右 ,自上而下; (4)  对于多个虚基类,构造函数的执行顺序仍然是先左后右 ,自上而下; (5)  对于非虚基类,构造函数的执行顺序仍是先左后右,自上而下; (6) 若虚基类由非虚基类派生而来,则仍然先调用基类构造函数,再调用派生类的构造函数; Object-Oriented Programming 汽车学院

(7) 关键字virtual 与继承方式关键字(public, private)的先后顺序无关紧要; 4.4.3 虚基类 (7) 关键字virtual 与继承方式关键字(public, private)的先后顺序无关紧要; class derived: virtual public base class derived: public virtual base (8)  一个基类在作为某些派生类虚基类的同时, 又可以作为另一些派生类的非虚基类。 Object-Oriented Programming 汽车学院

4.4.3 虚基类 【例4.17】虚基类的派生类构造函数的执行顺序。//P175 #include <iostream> using namespace std; class Base { public: Base(int sa ) { a=sa; cout<<"Base a="<<a<<endl; } private: int a; }; class Base1: virtual public Base{ Base1(int sa,int sb ):Base(sa) { b=sb; cout<<"Base1 b="<<b<<endl; } int b; Object-Oriented Programming 汽车学院

4.4.3 虚基类 运行结果: Base a=2 Base1 b=4 Base2 c=6 Derived d=8 class Base2: virtual public Base{ public: Base2(int sa, int sc ):Base(sa) { c=sc; cout<<"Base2 c="<<c<<endl; } private: int c; }; class Derived:public Base1, public Base2{ Derived(int sa, int sb, int sc, int sd ) :Base(sa), Base1(sa,sb), Base2(sa,sc) { d=sd; cout << "Derived d=" <<d << endl; } int d; int main( ) { Derived obj(2,4,6,8); return 0; } 运行结果: Base a=2 Base1 b=4 Base2 c=6 Derived d=8 Object-Oriented Programming 汽车学院

问题4. 虚基类的简单应用举例: 4.4.3 虚基类 【例4.18】类Data_rec是虚基类,它包含了所有派生类共有的数据成员; 1)职工类Employee和学生类Student为虚基类Data_rec的派生类; 2)在职大学生类E_Student是职工类Employee和学生类Student的共同派生类。 类层次图如下所示: Employee Student Data_rec E_Student virtual Object-Oriented Programming 汽车学院

4.4.3 虚基类 【例4.18】 #include <iostream> #include <string> using namespace std; class Data_rec{ public: Data_rec(string name1, char sex1, int age1) //构造函数 { name=name1; sex=sex1; age=age1; } protected: string name; //姓名 char sex; //性别 int age; //年龄 }; Object-Oriented Programming 汽车学院

4.4.3 虚基类 class Student: virtual public Data_rec{ public: Student(string name1, char sex1, int age1, string major1, double score1):Data_rec(name1, sex1, age1) { major=major1; score=score1; } protected: string major; //专业 double score; //成绩 }; Object-Oriented Programming 汽车学院

4.4.3 虚基类 class Employee: virtual public Data_rec{ protected: string dept; double salary; public: Employee(string name1, char sex1, int age1, string dept1, double salary1): Data_rec(name1, sex1, age1) { dept=dept1; salary=salary1; } }; class E_Student: public Employee, public Student{ E_Student(string name1, char sex1, int age1, string major1, double score1, string dept1, double salary1):Data_rec(name1, sex1, age1), Student(name1, sex1, age1, major1, score1), Employee(name1, sex1, age1, dept1, salary1) { } void print(); Object-Oriented Programming 汽车学院

4.4.3 虚基类 name= 张大明 sex= f age= 35 score= 95 major= 计算机 dept= 教务处 salary= 3500 void E_Student::print() { cout << "name= " << name << endl; cout << "sex= " << sex << endl; cout << "age= " << age << endl; cout << "score= " << score << endl; cout << "major= " << major << endl; cout << "dept= " << dept << endl; cout << "salary= " << salary << endl; }; int main() E_Student my_E_Student("张大明", 'f', 35, "计算机", 95, "教务处", 3500); my_E_Student.print(); return 0; } #include <iostream> #include <string> using namespace std; class Data_rec{ public: Data_rec(string name1, char sex1, int age1) //构造函数 { name=name1; sex=sex1; age=age1; } protected: string name; //姓名 char sex; //性别 int age; //年龄 }; class Student: virtual public Data_rec{ Student(string name1, char sex1, int age1, string major1, double score1):Data_rec(name1, sex1, age1) major=major1; score=score1; string major; //专业 double score; //成绩 class Employee: virtual public Data_rec{ string dept; double salary; Employee(string name1, char sex1, int age1, string dept1, double salary1): Data_rec(name1, sex1, age1) { dept=dept1; salary=salary1; } class E_Student: public Employee, public Student{ E_Student(string name1, char sex1, int age1, string major1, double score1, string dept1, double salary1):Data_rec(name1, sex1, age1), Student(name1, sex1, age1, major1, score1), Employee(name1, sex1, age1, dept1, salary1) { } void print(); void E_Student::print() cout << "name= " << name << endl; cout << "sex= " << sex << endl; cout << "age= " << age << endl; cout << "score= " << score << endl; cout << "major= " << major << endl; cout << "dept= " << dept << endl; cout << "salary= " << salary << endl; int main() E_Student my_E_Student("张大明", 'f', 35, "计算机", 95, "教务处", 3500); my_E_Student.print(); return 0; Object-Oriented Programming 汽车学院

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例

4.5 基类和派生类对象之间的赋值兼容关系 所谓赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。 这样,公有派生类实际上就具备了基类的所有特性,凡基类能解决的问题,公有派生类也能解决。

4.5 基类和派生类对象之间的赋值兼容关系 例如,下面声明的两个类: 根据赋值兼容规则, 以下几种情况是合法的: class Base{ //… }; class Derived:public Base{ 根据赋值兼容规则, 以下几种情况是合法的:

4.5 基类和派生类对象之间的赋值兼容关系 (1) 可以用派生类对象给基类对象赋值。例如: Base b; Derived d; b=d; (2) 可以用派生类对象来初始化基类的引用。例如: Derived d; Base &br=d;

4.5 基类和派生类对象之间的赋值兼容关系 (3) 可以把派生类对象的地址赋值给指向基类的指针。例如: Derived d; Base *bptr=&d; 这种形式的转换在实际应用程序中最常见到。 (4) 可以把指向派生类对象的指针变量的值赋值给指向基类对象的指针变量。例如: Derived *dptr; Base *bptr=dptr;

4.5 基类和派生类对象之间的赋值兼容关系 (5) 如果函数的形参是基类对象或基类对象的引用,在调用函数时可以用派生类对象作为实参。例如: class Base{ public: int i; }; class Derived: public Base{ …} void fun (Base &bb) { cout << bb.i << endl; } void main() { Derived d4; fun(d4); }

4.5 基类和派生类对象之间的赋值兼容关系 Base 100 Base 11 Base 22 Base 33 44 【例4.19】基类与派生类对象之间的转换。//P180 Base 100 Base 11 Base 22 Base 33 44 #include <iostream> using namespace std; class Base{ public: int i; Base(int x) { i=x; } void show() {cout << "Base " << i << endl;} }; class Derived: public Base{ Derived(int x): Base(x) { } //普通函数,形参为基类对象的引用 void fun(Base &bb) { cout << bb.i << endl; } int main() { Base b1(100); //定义基类对象b1 b1.show(); Derived d1(11); //定义派生类对象d1 b1=d1; //用派生类对象d1给基类对象b1赋值 Derived d2(22); //定义派生类对象d2 Base &b2=d2; //用派生类对象d2来初始化基类对象的引用b2 b2.show(); Derived d3(33); //定义派生类对象d3 //把派生类对象的地址&d3赋值给指向基类的指针b3 Base *b3=&d3; b3->show(); Derived d4(44); //定义派生类对象d4 fun(d4); //派生类的对象d4作为函数fun的实参 return 0; } #include <iostream> using namespace std; class Base{ public: int i; Base(int x) { i=x; } void show() {cout << "Base " << i << endl;} }; class Derived: public Base{ Derived(int x): Base(x) { } //普通函数,形参为基类对象的引用 void fun(Base &bb) { cout << bb.i << endl; } int main() { Base b1(100); //定义基类对象b1 b1.show(); Derived d1(11); //定义派生类对象d1 b1=d1; //用派生类对象d1给基类对象b1赋值 Derived d2(22); //定义派生类对象d2 Base &b2=d2; //用派生类对象d2来初始化基类对象的引用b2 b2.show(); Derived d3(33); //定义派生类对象d3 //把派生类对象的地址&d3赋值给指向基类的指针b3 Base *b3=&d3; b3->show(); Derived d4(44); //定义派生类对象d4 fun(d4); //派生类的对象d4作为函数fun的实参 return 0; }

4.5 基类和派生类对象之间的赋值兼容关系 说明 (1) 声明为指向基类对象的指针可以指向它的公有派生对象, 但不允许指向私有派生的对象。 (1) 声明为指向基类对象的指针可以指向它的公有派生对象, 但不允许指向私有派生的对象。 class base { // ...... }; class derive: private base { // ...... } void main() { base op1, *ptr; derive op2; ptr=&op1; ptr=&op2; //ERROR // ... ... }

4.5 基类和派生类对象之间的赋值兼容关系 (2) 允许将一个声明为指向基类的指针指向其公有派生类的对象, 但不能将一个声明为指向派生类对象的指针指向其基类的一个对象。 class Base { // ...... }; class Derive: public base { int main(){ Base obj1; Derive obj2, *ptr; ptr=&obj2; ptr=&obj1; //ERROR // ... ... return 0; } 可以把指向派生类对象的指针赋值给指向基类对象的指针。例如: Derive *dptr; Base *bptr=dptr; #include<iostream> using namespace std; class Base { // ...... }; class Derive: public Base { int main(){ Base obj1; Derive obj2, *ptr; ptr=&obj2; ptr=&obj1; //ERROR // ... ... //Derive *dptr; //Base *bptr=dptr; return 0; }

第4章 派生类和继承 4.1 派生类的概念 4.2 派生类的构造函数和析构函数 4.3 调整基类成员在派生类中的访问属性 4.4 多重继承 4.5 基类和派生类对象之间的赋值兼容关系 4.6 应用举例

4.6 应用举例 【例4.20】P182 1)建立基类Building,作为楼房类,这个基类中包含楼房层数、房间数、楼房总面积数等。 2)再建立派生类Home_Arch、Office_Building和Hospital,分别作为住宅楼类、办公类和医院类: (2.1)在类Home_Arch中,包含的内容有卧室数、客厅数、卫生间数和厨房数等; (2.2)在类Office_Building中,包含的内容有办公室数和会议室数等; (2.3)在类Hospital中,包含的内容有病房数手术室数等。

4.6 应用举例 #include<iostream> using namespace std; class Building{ //声明楼房类作为基类 public: Building(int f=0, int r=0, double a=0) { floors=f; rooms=r; j_area=a; } void Show_Info() { cout << "楼房层数: "<< floors << "层" << endl; cout << "房间数: " << rooms << "间" << endl; cout << "楼房总面积: " << j_area << "平方米" << endl; cout << "其中: "; } protected: int floors; int rooms; double j_area; };

4.6 应用举例 【例4.20】P182--02 class Home_Arch: public Building{ //声明住宅楼类Home_Arch作为公有派生类 public: Home_Arch(int f=0, int r=0, double a=0, int b=1, int p=1, int to=1, int k=1): Building(f, r, a) { bedrooms=b; parlor=p; toilets=to; kitchens=k; } void Show() { cout << endl; cout << "住宅楼: " << endl; Building::Show_Info(); cout << "卧室数: " << bedrooms << "间" << endl; cout << " 客厅数: " << parlor << "间" << endl; cout << " 卫生间数: " << toilets << "间" << endl; cout << " 厨房数: " << kitchens << "间" << endl; } private: int bedrooms; int parlor; int toilets; int kitchens; };

4.6 应用举例 【例4.20】P182--03 //声明办公楼类Office_Building作为公有派生类 class Office_Building: public Building{ public: Office_Building(int f=0, int r=0, double a=0, int o=0, int a_r=0): Building(f, r, a) { Office=o; assembly_room=a_r; } void Show() { cout << endl; cout << "办公楼: " << endl; Building::Show_Info(); cout << "办公室数: " << Office << "间" << endl; cout << " 会议室数: " << assembly_room << "个" << endl; } private: int Office; int assembly_room; };

4.6 应用举例 【例4.20】P182--04 //声明医院类Hospital作为公有派生类 class Hospital: public Building{ public: Hospital(int f=0, int r=0, double a=0, int s=0, int o=0): Building(f, r, a) { sickrooms=s; operating_rooms=o; } void Show() { cout << endl; cout << "医院: " << endl; Building::Show_Info(); cout << "病房数: " << sickrooms << "间" << endl; cout << " 手术室数: " << operating_rooms << "间" << endl; } private: int sickrooms; int operating_rooms; };

4.6 应用举例 运行结果: 住宅楼: 【例4.20】P182--05 楼房层数: 7层 房间数: 100间 楼房总面积: 12000平方米 其中: 卧室数: 3间 客厅数: 1间 卫生间数: 1间 厨房数: 1间 办公楼: 楼房层数: 4层 房间数: 80间 楼房总面积: 3500平方米 其中: 办公室数: 40间 会议室数: 12个 医院: 楼房层数: 10层 房间数: 300间 楼房总面积: 250000平方米 其中: 病房数: 200间 手术室数: 20间 4.6 应用举例 【例4.20】P182--05 int main() { Home_Arch home(7, 100, 12000, 3, 1, 1, 1); Office_Building office(4, 80, 3500, 40, 12); Hospital hosp(10, 300, 250000, 200, 20); home.Show(); office.Show(); hosp.Show(); return 0; } #include<iostream> using namespace std; class Building{ //声明楼房类作为基类 public: Building(int f=0, int r=0, double a=0) { floors=f; rooms=r; j_area=a; } void Show_Info() { cout << "楼房层数: "<< floors << "层" << endl; cout << "房间数: " << rooms << "间" << endl; cout << "楼房总面积: " << j_area << "平方米" << endl; cout << "其中: "; } protected: int floors; int rooms; double j_area; }; class Home_Arch: public Building{ //声明住宅楼类Home_Arch作为公有派生类 Home_Arch(int f=0, int r=0, double a=0, int b=1, int p=1, int to=1, int k=1): Building(f, r, a) { bedrooms=b; parlor=p; toilets=to; kitchens=k; } void Show() { cout << endl; cout << "住宅楼: " << endl; Building::Show_Info(); cout << "卧室数: " << bedrooms << "间" << endl; cout << " 客厅数: " << parlor << "间" << endl; cout << " 卫生间数: " << toilets << "间" << endl; cout << " 厨房数: " << kitchens << "间" << endl; private: int bedrooms; int parlor; int toilets; int kitchens; //声明办公楼类Office_Building作为公有派生类 class Office_Building: public Building{ Office_Building(int f=0, int r=0, double a=0, int o=0, int a_r=0): Building(f, r, a) { Office=o; assembly_room=a_r; } cout << "办公楼: " << endl; cout << "办公室数: " << Office << "间" << endl; cout << " 会议室数: " << assembly_room << "个" << endl; int Office; int assembly_room; //声明医院类Hospital作为公有派生类 class Hospital: public Building{ Hospital(int f=0, int r=0, double a=0, int s=0, int o=0): Building(f, r, a) { sickrooms=s; operating_rooms=o; } cout << "医院: " << endl; cout << "病房数: " << sickrooms << "间" << endl; cout << " 手术室数: " << operating_rooms << "间" << endl; int sickrooms; int operating_rooms; int main() Home_Arch home(7, 100, 12000, 3, 1, 1, 1); Office_Building office(4, 80, 3500, 40, 12); Hospital hosp(10, 300, 250000, 200, 20); home.Show(); office.Show(); hosp.Show(); return 0;

【例4.21】P185 4.6 应用举例 (2.1)职工类Employee和学生类Student为虚基类Data_rec的派生类, 1)建立一个简单的大学管理系统,其中有学生类、职工类、教师类和在职大学生类。类的继承关系如下图示: 2)类Data_rec是虚基类,它包含了所有派生类共有的数据成员: (2.1)职工类Employee和学生类Student为虚基类Data_rec的派生类, (2.2)教师类Teacher为职工类Employee的派生类, (2.3)在职大学生类E_Student是职工类Employee和学生类Student的共同派生类。 3)每个类定义了一个相对于特定类的不同的print函数,输出各类的数据成员。 Data_rec virtual virtual Employee Student Teacher E_Student

4.6 应用举例 【例4.21】P185--01 #include <iostream> #include <string> using namespace std; class Data_rec{ //声明基类Data_rec public: Data_rec(string name1, char sex1, int age1) //构造函数 { name=name1; sex=sex1; age=age1; } void print() { cout << "name: " << name << endl; cout << "sex: " << sex << endl; cout << "age: " << age << endl; protected: string name; //姓名 char sex; //性别 int age; //年龄 };

4.6 应用举例 【例4.21】P185--02 class Student: virtual public Data_rec //声明类Data_rec是Student的虚基类 { public: Student(string name1, char sex1, int age1, string major1, double score1): Data_rec(name1, sex1, age1) major=major1; score=score1; } void print() Data_rec::print(); cout << "score: " << score << endl; cout << "major: " << major << endl; protected: string major; //专业 double score; //成绩 };

4.6 应用举例 【例4.21】P185--03 class Employee: virtual public Data_rec//声明类Data_rec是Employee的虚基类 { public: Employee(string name1, char sex1, int age1, string dept1, double salary1): Data_rec(name1, sex1, age1) //构造函数 dept=dept1; salary=salary1; } void print() Data_rec::print(); cout << "department: " << dept << endl; cout << "salary: " << salary << endl; protected: string dept; //部门 double salary; //酬金 };

4.6 应用举例 【例4.21】P185--04 class Teacher: public Employee //声明类Teacher为类Employee的派生类 { public: Teacher(string name1, char sex1, int age1, string dept1, double salary1, string title1): Data_rec(name1, sex1, age1), Employee(name1, sex1, age1, dept1, salary1) title=title1; } void print() Employee::print(); cout << "title1: " << title << endl; protected: string title; //职称 };

4.6 应用举例 【例4.21】P185--05 //声明类E_Student为类Employee和类Student的派生类 class E_Student: public Employee, public Student { public: E_Student(string name1, char sex1, int age1, string major1, double score1, string dept1, double salary1): Data_rec(name1, sex1, age1), Student(name1, sex1, age1, major1, score1), Employee(name1, sex1, age1, dept1, salary1) { } void print() Student::print(); cout << "department: " << dept << endl; cout << "salary:" << salary << endl; };

4.6 应用举例 【例4.21】P185--06 int main() { Student my_Student("李晓敏", 'f', 22, "应用数学", 90); cout << "Student: " << endl; my_Student.print(); Employee my_Employee("黄百松", 'm', 55, "科研处", 5000); cout << "Employee: " << endl; my_Employee.print(); Teacher my_Teacher("王世明", 'm', 50, "管理学院", 8000, "教授"); cout << "Teacher: " << endl; my_Teacher.print(); E_Student my_E_Student("张大明", 'm', 35, "计算机", 95, "教务处", 3500); cout << "E_Student: " << endl; my_E_Student.print(); return 0; } #include <iostream> #include <string> using namespace std; class Data_rec{ //声明基类Data_rec public: Data_rec(string name1, char sex1, int age1) //构造函数 { name=name1; sex=sex1; age=age1; } void print() { cout << "name: " << name << endl; cout << "sex: " << sex << endl; cout << "age: " << age << endl; protected: string name; //姓名 char sex; //性别 int age; //年龄 }; class Student: virtual public Data_rec //声明类Data_rec是Student的虚基类 { Student(string name1, char sex1, int age1, string major1, double score1): Data_rec(name1, sex1, age1) major=major1; score=score1; Data_rec::print(); cout << "score: " << score << endl; cout << "major: " << major << endl; string major; //专业 double score; //成绩 class Employee: virtual public Data_rec//声明类Data_rec是Employee的虚基类 Employee(string name1, char sex1, int age1, string dept1, double salary1): Data_rec(name1, sex1, age1) //构造函数 dept=dept1; salary=salary1; cout << "department: " << dept << endl; cout << "salary: " << salary << endl; string dept; //部门 double salary; //酬金 class Teacher: public Employee //声明类Teacher为类Employee的派生类 Teacher(string name1, char sex1, int age1, string dept1, double salary1, string title1): Data_rec(name1, sex1, age1), Employee(name1, sex1, age1, dept1, salary1) title=title1; Employee::print(); cout << "title1: " << title << endl; string title; //职称 //声明类E_Student为类Employee和类Student的派生类 class E_Student: public Employee, public Student { E_Student(string name1, char sex1, int age1, string major1, double score1, string dept1, double salary1): Student(name1, sex1, age1, major1, score1), Student::print(); cout << "salary:" << salary << endl; int main() { Student my_Student("李晓敏", 'f', 22, "应用数学", 90); cout << "Student: " << endl; my_Student.print(); Employee my_Employee("黄百松", 'm', 55, "科研处", 5000); cout << "Employee: " << endl; my_Employee.print(); Teacher my_Teacher("王世明", 'm', 50, "管理学院", 8000, "教授"); cout << "Teacher: " << endl; my_Teacher.print(); E_Student my_E_Student("张大明", 'm', 35, "计算机", 95, "教务处", 3500); cout << "E_Student: " << endl; my_E_Student.print(); return 0;

运行结果: 4.6 应用举例 【例4.21】P185--07 Student: name: 李晓敏 sex: f age: 22 score: 90 major: 应用数学 Employee: name: 黄百松 sex: m age: 55 department: 科研处 salary: 5000 Teacher: name: 王世明 sex: m age: 50 department: 管理学院 salary: 8000 title1: 教授 E_Student: name: 张大明 age: 35 score: 95 major: 计算机 department: 教务处 salary:3500 Press any key to continue

Practice, Practice, and Practice Q & A Practice, Practice, and Practice Object-Oriented Programming 汽车学院 Object-Oriented Programming 汽车学院