VC++第11章继承和派生类2
《C#继承和接口》课件
继承与接口的使用
继承与接口的关系
派生类既可以继承基类,也可 以实现接口。
类实现接口
类通过实现接口的方式,来表 明它提供了该接口所定义的所 有方法和属性。
接口实现类
接口只定义方法和属性,而类 则需要实现具体的处理过程。
实战案例
1
需求说明
开发一个扫码点餐系统,支持顾客选择餐品、付款、生成订单、和查看历史订单等功 能。
C#继承和接口
C#继承和接口是面向对象编程中重要的概念。本课件将介绍继承、接口、抽 象类以及它们的应用场景和使用方法。
继承
概念
继承是指派生类获取基类成员 的过程。派生类可以获得基类 的属性、方法和字段。
单继承
C#只支持单继承。一个类只能 有一个基类。
多层继承
派生类可以派生出新的类,也 可以同时继承多个接口,形成 多层继承的关系。
接口定义一个合约,规定了实现它的 类型需要提供什么方法和属性。
接口继承
接口可以从一个或多个接口继承。
显式实现接口方法
如果一个类实现的多个接口中有相同 名称的方法,可以使用显式实现的方 式进行区分。
பைடு நூலகம்
接口与抽象类
抽象类和接口的区别
抽象类可以包含成员变量,但接口中没有成员变量。
抽象类和接口的应用场景
抽象类适合用于一组相关的类,而接口适合用于一组不同的类。
• 分继离承。会增加复杂度, 而接口一般只能有方 法和属性。
继承和接口应用的 场景
• 继承适用于类的重用 和拓展,接口适用于 不同类型的统一约束。
• 不同的应用场景需要 不同的设计方案。
继承和接口的对比
• 继承和接口可以结合 使用。
• 继承和接口都是面向 对象编程中的重要概 念,需要熟练掌握。
2.2 继承和派生类 (第二章 C++面向对象程序设计)
20、派生类是如何定义的?答:class classname:access-label base-class这里access-label是public、protected或private,base-class是已定义的类的名字。
21、派生类的继承方式有哪些?它们各有哪些特点?答:继承方式有public继承、protected继承、private继承。
1)公有继承:基类公有成员相当于派生类的公有成员;基类保护成员相当于派生类的保护成员;基类的私有成员,派生类内部成员无法直接访问。
2)私有继承:基类公有成员和保护成员都相当于派生类的私有成员,派生类只能通过自身的成员函数访问它们;基类的私有成员,无论派生类内部成员或派生类的对象都无法直接。
3)保护继承:基类公有成员和保护成员都相当于派生类的保护成员,派生类可以通过自身的成员函数或其子类的成员函数访问它们;基类的私有成员,无论派生类内部成员或派生类的对象都无法直接访问22、在定义派生类的过程中,如何对基类的数据成员进行初始化?答:调用基类的初始化函数,或者如果有权限直接访问该数据成员,那就直接赋值初始化。
23、在派生类中能否直接访问基类中的私有成员?在派生类中如何实现访问基类中的私有成员?答:不能。
为了实现访问基类的私有成员,可以(1)在类定义体中增加保护段(protected);(2)将需访问基类私有成员的派生类成员函数声明为基类的友元。
24、什么是虚基类?它的作用如何?答:在派生类继承基类时,加上一个virtual关键词则为虚基类继承,如:class derive : virtual public base{ };作用:当某类的部分或全部直接基类是从另一个基类共同派生而来时,这直接基类中,从上一级基类继承来的成员就拥有相同的名称,派生类的对象的这些同名成员在内存中同时拥有多个拷贝,同一个函数名有多个映射。
可以使用作用域分辨符来唯一标识并分别访问它们。
软件工程导论第11章
【还可以把适配接口再进一步细分为转换接口和扩充接口。转换接口, 是为了克服与表示方法、数据结构或硬件特点相关的操作给重用带来 的困难而设计的,这类接口是每个类构件在重用时都必须重新定义的 服务的集合。当使用C++语言编程时,应该在根类(或适当的基类)中, 把属于转换接口的服务定义为纯虚函数。如果某个服务有多种可能的 实现算法,则应该把它当作扩充接口。扩充接口与转换接口不同,并 不需要强迫用户在派生类中重新定义它们,相反,如果在派生类中没 有给出扩充接口的新算法,则将继承父类中的算法。当用C++语言实现 时,在基类中把这类服务定义为普通的虚函数。】
4. 弱耦合 耦合:指一个软件结构内不同模块之间互连的紧 密程度。 在面向对象方法中,对象是最基本的模块,因此, 耦合主要指不同对象之间相互关联的紧密程度。 弱耦合是优秀设计的一个重要标准。
5
对象之间的耦合分为两大类: (1) 交互耦合: 对象之间的耦合通过消息连接来实现。 使交互耦合尽可能松散,应遵守下述准则: 尽量降低消息连接的复杂程度。 应该尽量减少消息中包含的参数个数,降低参数的复 杂程度。 减少对象发送(或接收)的消息数。 (2) 继承耦合 与交互耦合相反,应该提高继承耦合程度。 通过继承关系结合起来的基类和派生类,构成系统中 粒度更大的模块。设计时应该使特殊类尽量多继承并 使用其一般化类的属性和服务,从而更紧密地耦合到 其一般化类。
13
2. 软件成分的重用级别 (1) 代码重用 源代码剪贴:最原始的重用形式。 复制或修改原有代码时可能出错,存在严重的配臵 管理问题,人们几乎无法跟踪原始代码块多次修改 重用的过程。 源代码包含:许多程序设计语言都提供包含库中 源代码的机制。配臵管理问题有所缓解,修改了库 中源代码之后,所有包含它的程序自然都必须重新 编译。 继承:利用继承机制重用类库中的类时,无须修 改已有的代码,就可以扩充或具体化在库中找出的 类,基本上不存在配臵管理问题。
VC 复习提要和重点
2、根据变量所占用内存的方式,变量分为 4 种类型:自动类型(auto)、静态类型(static)、
寄存器类型(register)以及外部类型(extern)。
例: #include <iostream.h>
void f (void)
{ static i“i=“<<i<<‘\n’;
#define 符号常量 表达式 如:#define PI 3.1415926
方法二:常量说明符 const 如:const int buf=512;
(三)变量的作用域和存储类型
1、作用域有 5 类:块作用域、文件作用域、函数作用域、函数原型作用域以及类的作用域。
注意:作用域运算符“::”仅用于全局标识符。
C++中编译预处理包括:宏定义、文件包含和条件编译。 特点:以#开头标识;每一条预处理指令各占一行,不是以分号结束
1、 文件包含
格式:# include “文件名” 或 # include <文件名>
2、宏定义。(只作简单替换)
基类和派生类
5
(1)公有继承(public)
当类的继承方式为公有继承时,基类的公有和保 护成员的访问属性在派生类中不变,而基类的私有 成员不可访问,
即基类的公有成员和保护成员被继承到派生类中 仍作为派生类的公有成员和保护成员,派生类的其 他成员可以直接访问它们。
具体赋值规则如下: 派生类的对象可以赋值给基类对象。 派生类的对象可以初始化基类对象的引用。 派生类对象的地址可以赋给指向基类对象的 指针。
15
例如: class A{...};
class B: public A
{void fun() {...}}; A a; B b; a=b; //将对象b中所含类A成员的值赋给对象a A &a1=b; //用派生类对象初始化基类对象的引用 A *pa =&b;
22
基类名1,继承方式2 基类名2,… {…} ;
{ 派生类类体
class C : public
};
A , private B
多重继承允许一个派生类同时继 {…} ; // C 公有
承多个基类中的成员,支持了软件 继承 A,私有继
的重用性,但也可能带来大量的二 承 B
义性问题。 17
复合与继承在软件渐增式开发中的应用
10
3.在派生类中重定义基类的函数
派生类自动继承了基类中定义的数据成员和成员函数。 如果派生类认为基类中某个成员函数的实现不能满足需 要,可以在派生类中重新定义该函数。
重定义基类的成员函数需要使用和该函数相同的函数 名和参数列表,如果参数列表不同,就是函数重载而不 是函数的重定义了。
C_C++程序设计与上机指导011
11.3.2 变量的引用
1. 引用的概念
引用是C++对C的一个重要扩充。引用就是为某个变量取个别名。 当定义一个引用后,引用作为目标变量的别名使用,对引用的改变实际 就是对目标变量的改变。 格式:<类型说明>&<变量名>=<变量名> 说明: • (1) 声明引用并不另行开辟内存单元,而是与目标变量代表同一单元。 • (2) 声明一个引用的同时必须对其进行初始化,且一旦初始化就不能 再作为其他变量的别名。
11.2
• • • • • • • •
简单的C++程序 简单的C++程序 C++
首先通过一个简单的程序来了解C++程序的结构特点。 程序的结构特点。 首先通过一个简单的程序来了解 程序的结构特点
输出一行字符。
#include <stdio.h> #include <iostream.h> /* 本程序的作用是输出一行字符 */ void main( ) { printf("This is a c++ program.\ n"); cout <<" This is a c++ program.\ n" ; //本行输出一行字符 } 运行结果:
11.3.4 内联函数
C++引入内联函数的目的是为了提高程序的运行效率。使用函数可 引入内联函数的目的是为了提高程序的运行效率。 引入内联函数的目的是为了提高程序的运行效率 以减少目标代码,实现代码共享, 以减少目标代码,实现代码共享,但函数的使用是通过函数调用实现 我们前面讲到,函数调用需要借助栈来进行参数传递, 的。我们前面讲到,函数调用需要借助栈来进行参数传递,并且伴随 有程序执行转移,这些工作都需要一定的时间开销。 有程序执行转移,这些工作都需要一定的时间开销。当一些函数使用 频率较高,而代码却相对较短时,就会严重影响程序的执行效率。 频率较高,而代码却相对较短时,就会严重影响程序的执行效率。为 引入内联函数。 在程序进行编译时, 此,C++引入内联函数。即:在程序进行编译时,编译器会将程序 引入内联函数 中出现的内联函数的调用表达式用函数体替换。 中出现的内联函数的调用表达式用函数体替换。 内联函数的定义方法很简单,只需在函数定义(或声明 或声明)前加关键字 内联函数的定义方法很简单,只需在函数定义 或声明 前加关键字 inline即可。定义方式有两种,一是声明同时定义函数体,另一种是 即可。 即可 定义方式有两种,一是声明同时定义函数体, 先声明再定义。 先声明再定义。 使用内联函数时应注意以下几点: 使用内联函数时应注意以下几点:
C++基类和派生类
C++基类和派⽣类整理⾃ 通过继承机制,可以利⽤已有的数据类型来定义新的数据类型。
所定义的新的数据类型不仅拥有新定义的成员,⽽且还同时拥有旧的成员。
我们称已存在的⽤来派⽣新类的类为基类,⼜称为⽗类。
由已存在的类派⽣出的新类称为派⽣类,⼜称为⼦类。
在++中,⼀个派⽣类可以从⼀个基类派⽣,也可以从多个基类派⽣。
从⼀个基类派⽣的继承称为单继承;从多个基类派⽣的继承称为多继承。
派⽣类的定义格式 单继承的定义格式如下: class <派⽣类名>:<继承⽅式><基类名> { <派⽣类新定义成员> }; 其中,<派⽣类名>是新定义的⼀个类的名字,它是从<基类名>中派⽣的,并且按指定的<继承⽅式>派⽣的。
<继承⽅式>常使⽤如下三种关键字给予表⽰: public 表⽰公有基类; private 表⽰私有基类; protected 表⽰保护基类; 多继承的定义格式如下: class <派⽣类名>:<继承⽅式1><基类名1>,<继承⽅式2><基类名2>,… { <派⽣类新定义成员> }; 可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于⼀个。
派⽣类的三种继承⽅式 公有继承(public)、私有继承(private)、保护继承(protected)是常⽤的三种继承⽅式。
1. 公有继承(public) 公有继承的特点是基类的公有成员和保护成员作为派⽣类的成员时,它们都保持原有的状态,⽽基类的私有成员仍然是私有的。
2. 私有继承(private) 私有继承的特点是基类的公有成员和保护成员都作为派⽣类的私有成员,并且不能被这个派⽣类的⼦类所访问。
3. 保护继承(protected) 保护继承的特点是基类的所有公有成员和保护成员都成为派⽣类的保护成员,并且只能被它的派⽣类成员函数或友元访问,基类的私有成员仍然是私有的。
C++中类继承public,protected和private关键字作用详解及派生类的访问权限
C++中类继承public,protected和private关键字作⽤详解及派⽣类的访问权限注意:本⽂有时候会⽤Visual Studio Code⾥插件的⾃动补全功能来展⽰访问权限的范围(当且仅当⾃动补全范围等价于对象访问权限范围的时候),但是不代表⽇常使⽤时只要是出现在⾃动补全范围内的可调⽤对象/成员都是可访问的。
⼀,公有继承#include<cstdio>#include<iostream>#include<string>#include<algorithm>#include<vector>class Base{public:int PublicBase;void PublicPrint() {std::cout << "PublicPrint()" << std::endl;}protected:int ProtectedBase;void ProtectedPrint() {std::cout << "ProtectedPrint()" << std::endl;}private:int PrivateBase;void PrivatePrint() {std::cout << "PrivatePrint()" << std::endl;}};class Derived : public Base{public:void DerivedPrint() {std::cout << "DerivedPrint()" << std::endl;std::cout << ProtectedBase << std::endl;//若要访问protected的数据成员需要通过派⽣类⾥的成员函数访问PublicPrint();ProtectedPrint();}};int main(void){Derived der;der.PublicPrint();der.PublicBase;//der.ProtectedBase; //不能直接访问protected数据成员//der.ProtectedPrint();//意思同上return0;} 公有继承的派⽣类可以直接访问基类的public中的数据成员和成员函数,不能直接访问protected中的数据成员和成员函数,若要访问protected的数据成员需要通过派⽣类⾥的成员函数访问。
关于VC语言中类的继承与模板的实例分析
信息 科 学 Il ;
科
关于 V C语言中类的继承与模板的实例分析
( 盐城 工学院, 江苏 盐城 2 40 ) 20 0
摘 要: 的 承与 板 C 言中 难 和 点 在 入学 C 的 承 模板 帮 我 好学 好V. 并 行大 类 继 模 是V 语 的 点 重 。 深 习V 类 继 与 可 助 们更 鼍 c 语
Sa k me e : tc mb r . 可简化了程序设计方法 ,显著提高软件的重用 以下为具体步骤 : 3 ( ) 基类 Ln L tLn Ls的实现类 I I 一 设计 i i。 i i k s k t 性, 叉使得软 件更容易维护 。 派生则是继承的直 用链表结构实现。 要求 I2 I 接产物 , 通过继承 已有 的—个或多个类来生一 似于实验五中的队列类 , 1 () 个新类 , 通过派生可创建一种类族 。它的实现 , 链表类具有以下 功能: 1能够在链表的头尾增 I I l 2 方便 了更大规模 的软件开发。因而类 的继承与 加节点 以及在链表头删除节点( )能够记录链 IO 用静 态成员 )3 能返 回链表 中 的节 () 模板 在类 的学习 中极其重要。下面我们具体谈 表 的个数 ( 点个数( ) 4 能查看链 表头节点的元素值( ) 5 能告 谈类及类 的继承与模板 。 f 用多文 件结构实现 程序。三个类 的定 4 ) 6 在链 表 在 VC中,这种将数据与处理这些 数据 的 知链表是否 为能告知链表是否为 空( ) 7 在链 表类 的析 义放在一个头文件中 , 的实现放在另一个 源 类 函数封装成—个整体 , 就构成一个类。或者说 , 类 的构造 函数 中初始化链表 ( ) 类 是对一组性质相 同事物 的程序描述 ,它由描 构函数中释放链表所有元素的空间。下面给出 文件中。主程序用于测试你所设计的三个类 的 测试内容包括如下 :) 队列 中加入几 1在 述该类事 物的共 同特性 的数据和处理这些数据 链 表类 的类定 义 ,我 们可 据定义 完全 实现该 正确性 。 个元 素 , p nQ ee 打 印队列 内容 , 用 r t uu 0 i 然后 再 的函数组成 。 一个类 可以根据需要 生成派生类 。 类 。 从队列 中取 出这些元素 , 看是否 正确 2 在栈 中 ) , 用链表实现的列 表类 个 派生类又可 以作为另—个 类的基类 , 一个 , 加入几个 元素 , p nS e 0 印栈 的内容, 用 r tak打 i t 然 基类可 以派生出若干个 派生类 , 这样可 以构成 casLn Ls I ls ik i t 后再从栈中取 出这些元素 , 看是否正确 3 测试 ) 定义链表节点类 型 了类树 。 继承常用来表示类属关系。 当从 已有 的 , , 取 队列 长度 的 函数 gt uuL n t 的正确 性 e e e eg 0 Q h 类 中派生 出新的类时 , 可对派生类傲几种变化 : tpd fsrc nd I yee t t oe u n a 4 测试 判断栈 是否 为空 的函数 e p 0 ) m t 的正确 y ( )可全部或部分地继承基类 的成员数据或成 i t d m; 1 性。 员 函数( ) 2 可增加新 的成员变量 ( ) 3可增加新 的 src o e n x tu tn e d ( 实 现提示 四) 成员 函数( ) 4 可重定义已有的成员 函数( ) 5 可改 }Ls aa o e it t d ; D N ( 1 )链表类的实现可 以参考实验五中 队列 变现有的成员属性 。 c + 在 + 中有两种继承 : 单一 , 义链表类 型 , 定 y  ̄ it tNo i t t; 类 的实现 。()测试 程序可 以用如下程序 : 2 继承( 一个派生类仅 由一个 基类派生 ) 和多重继 tp fL sDaa d e L sDaa 衢 n l d < o te m.> c u e i sr a h 承 ( 一个 派生类 由两个或更多个基类所派生 ) p oe t d 。 rtce : 衔n l d ”i l s. ” c u e l dit n h 派生类继 承了基类 的所有方法 ,另外派生类 自 itc ut _ n on; I J 表中元素的个数 it t aa n ed aa i a ;表头 、 D Lk k l, 表 vi an 身还 可定义所 需要 的不包 含在 父类 中 的新 方 Ls aa d t i H a .dtLnT i, o m i0 I d 法。 而模板是 c + + 语言—个重要特征。 模板使程 尾 指 针 Q ee q u u l= nw Q ee e u u; Sa k * l : n w tc ; tc s e Sa k t i Ls o n;/ 表个数 ac t 7 序员快速 建立具有类型安全 的类库集合和函数 s t i C u t /4 cu o t<< ’ .lJLit: < Ln Litg t sNu ’0丑 ss“ < ik s: eLit m— 1 : 集合。 它的实现 。 方便 了更大规 模的软件开发 。 p b c uh: 模 板也是 c + + 语言支持参 数化多态性 的工具 。 Ln Lsvi) , 造 函 数 ik it o ; , ( d 构 bm < nl 腧 出总 的列表数 e <e d; 将一段程序所处理的对象类型参 数化,就可 以 vr a Ln Ls vi) 晰 构 函数 iul— ik i(od;, t t f iti: O o n r( ;j<4 i+ , 队列 和栈中加 ;+) , 在 使这段程序能够处理某个类型范围内的各种类 vi p tal ( tnwD t) od uTi i e a ;们笙 尾加入一个 入 元 素 n a 表 型 的对象 , 这就是参数化多态性 。 被参数化 的一 新 元素 f1 > n uu (; q - e Q eei ) 段程序将会处理一定 范围内的若 干种不 同类型 vi uH a itnwD t) od p ted( e a ;们笙 头插入一个 s一 ps(; n a 表 l > uhi ) 的对象 ,即对 于一定 范围内的若干不 同类型 的 新 元素 ) 对象 的某种 操作将对 应 着一个 相 同结构 的实 it e ed( i ; / n gt a v d / H o ) 从表头取 出一个元素 tu < ” u u lnt: < q - gtu u — o t< Q e e e g ” ‘ l >eQ e e h 现。 而模 板这种工具就是用来解决这个问题 的。 i ek ed o ); 看表头 元素的值 , n peHa( i , t vd 鹰 假定 L n t 0< nl , 出队列 长度和队列中元 eg <e d 墒 h ; 下面 可以通 过设计 一个基类 , 完成 队列 和 列表至少有一个 元素 素个数 栈共 同的功 能,然后分别派生 出队列类和栈类 bo m t ;/ ole py() / 检查列 表是 否空 q 一 pi Q e e ; 腧 出栈 的内容 l > r t uu0 n 这两个派生类 。 这样可减少代码 , 提高效率 。 设 i e l C u t ;, n gt e o n t E m 0 , 取列表元素个 数 cu < ”tc o :”< s- tp < ed; ot< S k tp a < l >o0 < nl 计 的基类也可 以用于派生 出其他类。本 实例要 s t n eLs u e0 , ti itgtit mbr ;, ac N 取列 表个 数 s一 pitte0 / 出队列和栈中的元素 l > r Sak ; / �
继承与派生类答案
继承与派生类知识要点1.掌握继承和派生的定义,派生类的定义方法。
(1)掌握继承的两种类型:单继承和多继承。
(2)掌握private,public,protected三种继承方式的特点。
继承方式决定了基类中的成员在派生类中的属性。
三种继承方式的共同点:基类的private成员在派生类中不可见。
区别:对于私有继承,基类的public、protected成员在派生类中作为private成员;对于公有继承,基类的public、protected成员在派生类中访问属性不变;对于保护继承,基类的public、protected成员在派生类中作为protected成员。
(3)掌握派生类中的构造函数和析构函数的使用。
基类的构造函数和析构函数不能继承,所以必要时在派生类中定义自己的构造函数和析构函数。
派生列的构造函数完成基类中新增数据成员和基类数据成员的初始化,基类数据成员的初始化通过基类构造函数来实现。
(4)掌握派生类的同名覆盖规则。
(5)掌握赋值兼容规则。
基类对象可以使用公有派生类对象来代替,包括:派生类对象可以赋值给基类对象;派生类对象可以初始化基类对象的引用;基类类型指针可以指向派生类对象。
2.掌握多重继承的概念、定义方法、多重继承派生类构造函数的执行顺序。
派生类构造函数的执行顺序是先执行所有基类的构造函数(顺序按照定义派生类时指定的各基类顺序),在执行对象成员所在类的构造函数(顺序按照他们在类中的声明顺序),最后执行派生类构造函数体中的内容。
3.掌握虚基类的概念和定义方法。
在多重继承中,如果多条继承路径上有一个公共的基类,则在这些路径的汇合点上的派生类会产生来自不同路径的公共基类的多个拷贝,如果用virtual把公共基类定义成虚基类,则只会保留公共基类的一个拷贝。
典型例题分析与解答例题1:下列对派生类的描述中,()是错误的。
A.一个派生类可以作为另一个派生类的基类B.派生类至少有一个基类C.派生类的成员除了它自己的成员外,还包含了它的基类成员D.派生类中继承的基类成员的访问权限到派生类保持不变答案:D分析:一个派生类可以作为另一个派生类的基类。
VC习题参考答案
VC习题参考答案1.7指针和引用55.已知intd=5,某pd=&d,b=3;求下列表达式的值。
A.某pd某bB.++某pd-bC.某pd++D.++(某pd)答:15,3,5,656.选择填充。
(1)选择正确的说明语句为()。
A.intN['b'];B.intN[4,9];C.intN[][];D.int某N[10];答:B(2)若有定义:inta=100,某p=&a;则某p的值是()。
A.变量p的地址B.变量a的地址值C.变量a的值D.无意义答:C.(3)下述程序的输出结果是()。
#includevoidmain(){inta[5]={2,4,6,8,10};int某p=a,某某q=&p;cout<A.4,4B.2,2C.4,2D.4,5答:B(4)下述程序片段的输出是()。
inta[3][4]={{1,2,3,4},{5,6,7,8}};int某,某p=a[0];某=(某p)某(某p+2)某(某p+4);cout<A.15B.14C.16D.13答:A(5)若有以下定义,则下列对数组引用正确的是()。
int(某q)[3]=newint[2][3];A.q[2][3]B.某qC.某(某q+2)D.某(某(q+2)+3)答:C(6)若要用如下程序片段使指针变量p指向一个存储动态分配的存储单元:float某p;p=(float某)newfloat;则空白处应填入:A.float某B.某floatC省略;D.(float)(7)下列表示引用的方法中,()是正确的。
已知:intm=10;A.int&某=m;B.int&y=10;C.int&z;D.float&t=&m;答:A57.分析下列程序的结果。
#includeint&fun(intn,int[]){int&m=[n];returnm;}voidmain(){int[]={15,4,3,2,1,0};fun(3,)=10;cout<答:1058.用指针作为函数的参数,设计一个实现两个参数交换的函数。
VC++资源管理器
static CImageList * m_gpLargeImageList; //大图标链表 static CImageList * m_gpSmallImageList; //小图标链表
执行“转到”操作
树形控件
显示文件夹层次列表
列表控件
显示文件列表
Visual C++简明教程 再利用 MFC ClassWizard 将控件与主对话框类的成员变量关联起来。在 ClassWizard
对话框上的 Member Variable 选项卡进行关联操作,如图 11-8 所示。
图 11-8 为对话框控件添加关联变量
选择主菜单上的 Insert 命令,将弹出 Insert 子菜单;弹出的子菜单上,选择 New Class 命令,将弹出 New Class 对话框。在 New Class 对话框的 Class Type 下拉列表框中选择 Generic Class,在编辑框 Name 中输入 CSystemImageList,编辑框 Derived From 中输入 CObject,派生类型下拉列表框选则 Public。单击 OK 按钮,向工程添加系统图标列表 CSystemImageList 类。如图 11-10 所示。
表 11-2 菜单 IDR_MENU_MAINFRAME 清单
菜单 ID
菜单名称
用途
IDM_FILE_OPEN
打开
打开目录
IDM_FILE_CLOSE
关闭
关闭目录
IDM_EDIT_COPY
拷贝
拷贝选取的文件
软件工程导论(第11章)
3. 信息隐蔽
在面向对象方法中,信息隐蔽通过对象的封
装性实现:类结构分离了类的接口与类的实
现,从而支持了信息隐蔽。
4. 弱耦合
弱的耦合可以提高软件模块的独立性,避免 某一部分模块发生变化对其它模块有较大的影 响。
一般来说,对象间的耦合有两大类:
A.交互耦合:对象间的耦合通过信息连接来
实现。应使交互耦合尽量松散。
2. 一般—特殊结构的深度应适当
中等规模的系统中,类等级层次数应保持 为7±2。不是必要情况,不应该随意创建派生类;
3. 设计简单的类:设计小而简单的类,便于
开发和管理;
1)避免包含过多的属性; 2)有明确的定义; 3)尽量简化对象之间的合作关系; 4)不要提供太多服务。
4. 使用简单的协议:设计简单的类接口,发送 的消息中参数要少。 5. 使用简单的服务:编写实现每一个服务时, 避免复杂的语句和结构; 6. 把设计变动减至最小。
2.
两个方向的关联都用属性实现,这种方法能 实现快速访问。
3.
用独立的关联对象实现双向关联。关联对象 不属于相互关联的任何一个类,它是独立的 关联类的实例 。
40
41
4、关联对象的实现
关联对象的实现方法取决于关联的阶数:
一对一关联:
• 关联对象可以与参与关联的任一个对象合并。
一对多关联:
• 关联对象可以与“多”端对象合并。
11.9 设计类中的服务 11.9.1 确定类中应有的服务 11.9.2 设计实现服务的方法
1. 设计实现服务的算法
1)算法复杂度;
2)容易理解、容易实现;
3)容易修改;
2. 选择数据结构 3. 定义内部类和内部操作
派生与继承
继承与派生
(2)改造。改造是指对吸收进来的基类成员的改 改造。 改造 造。它包括两个方面:一个是对基类成员访问 它包括两个方面: 控制的调整, 控制的调整,它是通过派生类定义时的继承方 式来确定。另一个就是对基类成员的隐藏, 式来确定。另一个就是对基类成员的隐藏,即 在派生类中声明一个与基类成员同名的新成员, 在派生类中声明一个与基类成员同名的新成员, 这个新成员就隐藏了上层的所有同名成员。 这个新成员就隐藏了上层的所有同名成员。这 时,在派生类中或者通过派生类的对象来直接 使用该成员名, 使用该成员名,就只能访问到派生类中声明的 同名成员,这称为同名隐藏或同名覆盖。 同名成员,这称为同名隐藏或同名覆盖。
继承与派生
继承性的具体实现也就是一个派生类的建立过程。 继承性的具体实现也就是一个派生类的建立过程。 class 派生类名 : 继承方式 基类名 继承方式 基类名 基类名1, 基类名2, … , 继承方式 基类名 基类名n { 新增派生类成员声明; 新增派生类成员声明 }; 继承方式关键字有三个: 继承方式关键字有三个:public、private、protected。 、 、 。 继承方式关键字只对紧随其后的基类起作用。 继承方式关键字只对紧随其后的基类起作用。 在继承与派生的过程中,一个基类可以派生出多个派生类, 在继承与派生的过程中,一个基类可以派生出多个派生类, 每一个派生类又可以作为基类再派生出新的派生类, 每一个派生类又可以作为基类再派生出新的派生类,基类和 派生类是相对而言的。这样,一代一代地派生下去, 派生类是相对而言的。这样,一代一代地派生下去,就形成 了一个相互关联的有层次的类的家族,称为类族。在类族中, 了一个相互关联的有层次的类的家族,称为类族。在类族中, 作为上下层直接联系而参与派生出某类的基类称为该派生类 的直接基类, 的直接基类,而基类的基类甚至更高层的基类则称为间接基 类。
新标准C++程序设计5. 继承和派生
5
需要继承机制的例子
而不同的学生,又有各自不同的属性和方法 研究生 导师 系 大学生 系 中学生 竞赛特长加分
6
需要继承机制的例子
➢如果为每类学生都从头编写一个类,显然会有 不少重复的代码,浪费。
7
需要继承机制的例子
➢如果为每类学生都从头编写一个类,显然会有 不少重复的代码,浪费。
class CPoint {
double x,y; };
class CCircle:public CPoint {
double r; };
31
复合关系的使用
几何形体程序中,需要写“点”类,也需要写“圆”类
class CPoint {
double x,y; };
class CCircle:public CPoint {
class CStudent { private: string name; string id; //学号 char gender; //性别,'F'代表女,'M'代表男 int age; public: void PrintInfo(); void SetInfo( const string & name_,const string & id_, int age_, char gender_ ); string GetName() { return name; }
int v3; };
13
派生类对象的内存空间
派生类对象的体积,等于基类对象的体积,再加上派 生类对象自己的成员变量的体积。在派生类对象中,包 含着基类对象,而且基类对象的存储位置位于派生类对 象新增的成员变量之前。
c++继承与派生习题答案
1.概念填空题1。
1在C++中,三种派生方式的说明符号为public、private、protected不加说明,则默认的派生方式为private。
1。
2当公有派生时,基类的公有成员成为派生类的公有成员;保护成员成为派生类的保护成员;私有成员成为派生类的不能直接访问成员。
当保护派生时,基类的公有成员成为派生类的保护成员;保护成员成为派生类的保护成员;私有成员成为派生类的不能直接访问成员.1.3 派生类的构造函数一般有3项工作要完成:首先基类初始化,其次成员对象初始化,最后执行派生类构造函数体.1.4多继承时,多个基类中的同名的成员在派生类中由于标识符不唯一而出现二义性。
在派生类中采用虚基类或作用域分辨符来消除该问题.2.简答题2.1 派生类如何实现对基类私有成员的访问?2。
2什么是类型兼容规则?2.3派生类的构造函数是怎样的执行顺序,析构函数的执行顺序是如何实现的?2.4继承与组合之间的区别与联系是什么?2.5什么是虚基类?它有什么作用?含有虚基类的派生类的构造函数有什么要求,什么是最远派生类,建立一个含有虚基类的派生类的对象时,为什么由最远派生类的构造函数负责虚基类的初始化?3.选择题3.1下面对派生类的描述中,错误的是(D ).A.一个派生类可以作为另外一个派生类的基类B.派生类至少有一个基类C.派生类的成员除了它自己的成员外,还包含了它的基类的成员D.派生类中继承的基类成员的访问权限到派生类中保持不变3.2下列对友元关系叙述正确的是(A)。
A.不能继承B.是类与类的关系C.是一个类的成员函数与另一个类的关系D.提高程序的运行效率3。
3当保护继承时,基类的(B)在派生类中成为保护成员,不能通过派生类的对象来直接访问。
A.任何成员B.公有成员和保护成员C.公有成员和私有成员D.私有成员3.4设置虚基类的目的是(B).A.简化程序B.消除二义性C.提高运行效率D.减少目标代码3.5在公有派生情况下,有关派生类对象和基类对象的关系,不正确的叙述是( C )。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
初始化基类成员
派生类的构造函数的一般格式为: ClassName::ClassName(args):Base1(args1),Base2(args2), ...,Basen(argsn) 初始化成员列表 { ... //初始化派生类中的其它数据成员 }
若基类的构造函数的实参为空时,该基类的构造函数的调用 可从初始化成员列表中删除
26
class A { public: int x; void show(){cout<<"x="<<x<<endl;} A(int a){x=a;} A(){} }; calss B 编译错误!!! { public: int x; void show(){cout<<"x="<<x<<endl;} B(int a){x=a;} B(){} };
不可见
13
11.1.2 抽象类与保护的成员函数
当定义了一个类,这个类只能用作基类来派生出新 的类,而不能用这种类来定义对象时,称这种类为 抽象类. 实现方法: 把一个类的构造函数或析构函数的访问权限定 义为保护,这种类为抽象类。因这种类不能产生 对象,只能用来派生其它类。
14
11.1.2 单继承-小结
例:p248
24
11.3 冲突、支配规则和赋值兼容性
支配规则:在C++中,允许派生类中新增加的成员 名与其基类成员名相同,这种同名并不产生冲突。当 没有使用作用域运算符时,则派生类中定义的成员名 优先于基类中的成员名,这种优先关系称为支配规则。 赋值兼容规则:同类型的对象之间可相互赋值,派 生类的对象与基类对象能否相互赋值呢?赋值兼容规 则要讨论的问题
4
11.1.2 单继承—公有派生(public)
基类的private成员属于基类私有,不被继 承, public和protected成员的访问属性在 公有派生类中保持不变。 派生类中的成员函数可以直接访问基类中的 public和protected成员,但不能访问基类 的private成员。 外界通过派生类的对象只能访问基类的 public成员。
19
11.2 基类成员的初始化
问题:派生类和基类都有构造函数,如何初始化派生 类对象?
系统一方面调用基类的构造函数初始化派生类中的基 类成员,另一方面调用派生类的构造函数初始化派生类中 新增加的成员数据。
实例化派生类时,常常需要使用基类的构造函数, 而这些构造函数常常需要参数。如何向基类构造函 数传递参数呢? 解决方法:":"表示法向基类传递参数
16
class high { float h; public: high(float a){h=a;} void sethigh(float a){h=a;} float gethigh(){return h;} }; class column:public circle,private high { float V; public: column(float a,float b,float c,float d) :circle(a,b,c),high(d) {V=Area()*gethigh();} float getv(){return V;} };
27
class C:public A, public B { public: int y; void Setx(int a){x=a;} void Sety(int b){y=b;} int Gety(){return y;} }; main() { C c1; c1.Setx(10); //类C有两个x,给哪一个x赋值? c1.Show(); //显示哪一个x值? }
7
//现在类second相当于如下的声明 class second { private: int y1,y2; int w,h; void SetY(int cy1,int cy2); public: int z1,z2; void SetZ(int cz1,int cz2); };
8
class first { private: int x1,x2 void SetX(x1,x2); protected: int w,h; public: int y1,y2; void SetY(int cy1,cy2); }; class second:private first { public: int z1,z2; void SetZ(int cz1,int cz2); };
基类中不能被继承的成份:
基类中的私有(private后面)的成员。 构造函数:派生类不能继承基类的构造函数,但在产 生派生类对象时会自动调用基类的构造函数。 析构函数:派生类不能继承基类的析构函数,但在撤 消派生类对象时会自动调用基类析构函数。 用户定义的新操作符(后面讲) 用户定义的赋值符(后面讲) 友元关系:父母的朋友不一定是子女的朋友。
15
11.1.3 多重继承
class circle 一个派生类有多个基类,称为多重继承 { float x,y,r; public: circle(float x1,float y1,float r1) {x=x1;y=y1;r=r1;} void setx(float a){x=a;} void sety(float b){x=b;} void setr(float c){x=c;} float getx(){return x;} float gety(){return y;} float getr(){return r;} float Area(){return 3.14159*r*r;} }
21
class First { int a,b,c; public: First(int x,int y,int z){a=x;b=y,c=z;} }; class Second:public First { int value; public: Second(int d):First(d,d+1,d+5){value=d;} Second(int d,int e); }; ///////////////////// Second::Second(int d,int e):First(d,e,13) { value=d+e; 22 }
5
class first { private: int x1,x2 void SetX(x1,x2); //现在类second相当于如下的声明 protected: class second int w,h; { public: protected: int y1,y2; int void SetY(int cy1,cy2); w,h; }; public: class second:public first y1,y2; int { int z1,z2; public: void SetY(int cy1,int cy2); int z1,z2; void SetZ(int cz1,int cz2); void SetZ(int cz1,int cz2); }; };
10
//现在类second相当于如下的声明 class second { protected: int w,h; int y1,y2; void SetY(int cy1,int cy2); public: int z1,z2; void SetZ(int cz1,int cz2); };
11
class first { private: int x1,x2 void SetX(x1,x2); protected: int w,h; public: int y1,y2; void SetY(int cy1,cy2); }; class second:protected first { public: int z1,z2; void SetZ(int cz1,int cz2); };
9
11.1.2 单继承--保护派生(protected)
基类的private成员属于基类私有,不被继承, public和protected成员都以protected身 份出现在派生类中。 派生类中的成员函数可以直接访问基类中的 public和protected成员,但不能访问基类的 private成员。 外界通过派生类的对象不能访问基类中的任何成 员。
6
11.1.2 单继承—私有派生(private)
基类的private成员属于基类私有,不被继承, public和protected成员都以private身份出现 在私有派生类中。 派生类中的成员函数可以直接访问基类中的 public和protected成员,但不能访问基类的 private成员。 外界通过派生类的对象不能访问基类中的任何 成员。
cout<<"area="<<a1.Area()<<endl; cout<<"high= " <<b1.gethigh()endl; cout<<"volume="<<c1.getv()<<endl; }
18
X=6 Y=8 r=9
Area=254.469
High=23 Voiume=113.097
28
11.3.1 冲突—作用域分辨
解决冲突的办法:
让各基类中的成员名各不相同 在各基类中,均把成员数据说明为私有的,另提 供公有函数访问私有成员 使用作用域分辨符 "::"
一般
特殊
3
11.1.1 继承的基本概念 派生类名
基类(父类)类名
派生类的定义: class A:继承方式 B1 ,继承方式 B2,…] { public:公有继承 //类A特有成员定义; private:私有继承 } 三种继d:保护继承