5.2 基类和派生类
- 格式:doc
- 大小:73.00 KB
- 文档页数:3
基类和派⽣类
1.什么是基类?
在⾯向对象设计中,被定义为包含所有实体共性的class类型,被称为“基类”。
-百度百科
简单理解,即⽗类(相对派⽣类)
2.什么是派⽣类?
利⽤继承机制,新的类可以从已有的类中派⽣。
那些⽤于派⽣的类称为这些特别派⽣出的类的“基类”。
简单理解,即⼦类(相对基类)
3.两者关联
基类和派⽣类是⼀个相对的关系。
基类和派⽣类反映了类与类的继承关系,是相对⽽⾔的。
基类⼜称⽗类,是被派⽣类继承的类。
派⽣类⼜称⼦类,是从⼀个已有类的基础上创建的新类,新类包含基类的所有成员,并且还添加了⾃⼰的成员。
4.实际例⼦
假设有两个类A和B,A和B都需要实现⼀个打印的功能,原始的做法是A写⼀个打印函数,B也写⼀个打印函数。
两个类还好可以写,但多了就特别⿇烦。
这个时候我们就可以写⼀个类C,C⾥⾯写⼀个打印函数。
A和B分别继承C,这样A和B就不要写打印函数了。
这样即节省了代码,⼜优化了结构。
上⾯的情况,C是A和B的基类,A和B是C的派⽣类。
一选择题(共 45题)1.对类的构造函数和析构函数描述正确的是()。
A.构造函数可以重载,析构函数不能重载√B.构造函数不能重载,析构函数可以重载C.构造函数可以重载,析构函数也可以重载D.构造函数不能重载,析构函数也不能重载2.继承具有(),即当基类本身也是某一个类派生类时,底层的派生类也会自动继承间接基类的成员。
A)规律性 B.传递性√ C.重复性 D.多样性3.假设OneClass为一个类,则该类的复制初始化构造函数的声明语句为()。
(OneClass p); B. OneClass& (OneClass p );C. OneClass(OneClass & p);√D. OneClass (OneClass * p);4.对于结构中定义的成员,其默认的访问权限为()。
B. protected D. static5.下面对静态数据成员的描述中,不正确的是()。
A.静态数据成员可以在类体内进行初始化√B.静态数据成员不可以在类体内进行初始化C.静态数据成员能受private控制符的作用D.静态数据成员调用前必须初始6. C++中的类有两种用法:一种是类的实例化,即生成类对象,并参与系统的运行;另一种是通过()派生了新的类。
A.复用B.继承√C.封装D.引用7. 假定AA为一个类,a为该类公有的数据成员,x为该类的一个对象,则访问x对象中数据成员a 的格式为()。
A. x(a)B. x[a]C. x->aD. √9. 对于一个类的构造函数,其函数名与类名( )。
A. 完全相同√B. 基本相同C. 不相同D. 无关系10. 一个类的构造函数通常被定义为该类的( )成员。
A. 公有√B. 保护C. 私有D. 友元11. 一个类的析构函数通常被定义为该类的( )成员。
A. 私有B. 保护C. 公有√D. 友元12. 一个类的静态数据成员所表示属性 ( )。
A. 是类的或对象的属性B. 只是对象的属性C. 只是类的属性√D. 类和友元的属性13.类的析构函数的作用是()。
第5章图形绘制在Visual C++6.0中,掌握图形程序设计方法是非常重要的。
因为图形在任何一个可视化工程项目中都是不可缺少的。
CDC(设备环境)类封装了图形绘制所需要的各种操作。
本章我们将通过实际例子和较详细的阐述,来了解和掌握如何使用设备环境类(CDC)及图形设备接口(GDI)进行图形绘制。
5.1 设备环境与设备环境类(CDC)5.1.1 设备环境设备环境也称设备上下文(Device Context,简称DC),是计算机物理设备的代表,也是图形设备接口的主要组成部分。
由于Windows是一个与设备无关的操作系统,即Windows不允许直接访问硬件,如果用户想将文本和图形绘制到显示器或其它设备中去,必须通过“设备环境”这个抽象层与硬件进行通信,设备上下文对象的作用就是实现Windows的设备无关性,任何向屏幕上进行输出的功能都要间接地通过它来完成。
设备上下文是Windows的一种数据结构,它包含了有关如显示器或打印机等设备的绘图属性信息。
所有绘画都是通过设备上下文对象来实现的,该对象封装了Windows的画线、图形和文本的API函数。
设备上下文允许在Windows下独立于设备的绘画。
设备上下文不仅能够被用来在屏幕上绘画,它也可以将绘画输出到打印机和图元文件中。
5.1.2 设备环境类设备环境类CDC直接继承于CObject类,该类定义了一类设备对象。
CDC对象提供了非常多的成员函数,与设备环境的显示器、打印机等一起工作。
例如,如果要在显示器等设备上绘制图形,我们可以用MFC提供的设备环境类CDC类,因为CDC类中包含了绘图所需要的所有成员函数。
同时。
MFC还提供了以下几个CDC的派生类:1、CPaintDC类此类比较特殊,它的构造函数和析构函数都是针对OnPaint进行的。
用户一旦获得相关的CDC指针,就可以将它当做任何设备环境(包括屏幕、打印机)指针来使用,CPaintDC类的构造函数会自动调用BeginPaint,而它的析构函数则会自动调用EndPaint。
基类和派生类析构函数释放顺序
在C++中,一个类的析构函数用于释放该类所占用的资源。
当一个类被继承时,派生类可能会继承基类的一些资源,因此在析构派生类时需要考虑基类的析构函数的调用顺序。
一般来说,C++中的析构函数调用顺序与构造函数相反。
也就是说,先构造的对象后析构,后构造的对象先析构。
当一个派生类的对象被释放时,先调用派生类的析构函数,然后再调用基类的析构函数。
这意味着基类的析构函数应该在派生类的析构函数之前被调用。
但是,当一个派生类继承多个基类时,就需要注意它们的析构函数的调用顺序了。
C++规定,派生类析构函数应该按照基类的声明顺序调用基类的析构函数。
也就是说,先调用最后声明的基类的析构函数,然后再调用它的上一个基类的析构函数,直到最先声明的基类的析构函数被调用。
需要注意的是,如果基类的析构函数不是虚函数,那么在通过基类的指针或引用释放派生类的对象时,只会调用基类的析构函数,而不会调用派生类的析构函数。
因此,为了避免内存泄漏,基类的析构函数应该声明为虚函数。
综上所述,派生类的析构函数应该按照基类的声明顺序依次调用基类的析构函数,并且基类的析构函数应该声明为虚函数,以确保在释放派生类对象时能够正确释放资源。
- 1 -。
C++基类和派⽣类整理⾃ 通过继承机制,可以利⽤已有的数据类型来定义新的数据类型。
所定义的新的数据类型不仅拥有新定义的成员,⽽且还同时拥有旧的成员。
我们称已存在的⽤来派⽣新类的类为基类,⼜称为⽗类。
由已存在的类派⽣出的新类称为派⽣类,⼜称为⼦类。
在++中,⼀个派⽣类可以从⼀个基类派⽣,也可以从多个基类派⽣。
从⼀个基类派⽣的继承称为单继承;从多个基类派⽣的继承称为多继承。
派⽣类的定义格式 单继承的定义格式如下: class <派⽣类名>:<继承⽅式><基类名> { <派⽣类新定义成员> }; 其中,<派⽣类名>是新定义的⼀个类的名字,它是从<基类名>中派⽣的,并且按指定的<继承⽅式>派⽣的。
<继承⽅式>常使⽤如下三种关键字给予表⽰: public 表⽰公有基类; private 表⽰私有基类; protected 表⽰保护基类; 多继承的定义格式如下: class <派⽣类名>:<继承⽅式1><基类名1>,<继承⽅式2><基类名2>,… { <派⽣类新定义成员> }; 可见,多继承与单继承的区别从定义格式上看,主要是多继承的基类多于⼀个。
派⽣类的三种继承⽅式 公有继承(public)、私有继承(private)、保护继承(protected)是常⽤的三种继承⽅式。
1. 公有继承(public) 公有继承的特点是基类的公有成员和保护成员作为派⽣类的成员时,它们都保持原有的状态,⽽基类的私有成员仍然是私有的。
2. 私有继承(private) 私有继承的特点是基类的公有成员和保护成员都作为派⽣类的私有成员,并且不能被这个派⽣类的⼦类所访问。
3. 保护继承(protected) 保护继承的特点是基类的所有公有成员和保护成员都成为派⽣类的保护成员,并且只能被它的派⽣类成员函数或友元访问,基类的私有成员仍然是私有的。
西安石油大学大二(上)C++面向对象程序设计课件第5章习题习题5基本概念问题:5.1填空:(1)派生类的成员函数可以直接访问基类的成员,不能直接访问基类的______成员。
(2)保护继承时,基类的成员成为派生类中的受保护成员,派生类对象不能直接访问基类成员。
(3)在定义一个派生类时,使用__________关键字或者不显式地使用它则表示为__________继承。
(4)如果在多个基类及其派生类中定义了具有相同名称的成员函数,则在访问相应的函数___________________。
(5)若要保证一个公共的基类在派生类中只产生一个基类子对象,则必须都以____________的方式直接继承它。
5.2多项选择题:(1)从一个基类派生出的各个类的对象之间()。
a、共享所有成员变量,每个对象还包含基类的所有属性。
B.共享一些成员变量,每个对象也包含基类的所有属性。
C.不共享任何成员变量,但每个对象还包含基类的所有属性。
D.共享一些成员变量和成员函数(2)如果是类b在类a的基础上构造,那么,就称()。
a.类a为基类或父类,类b 为超类或子类b、类A是基类、父类或超类,类b是派生类或子类,C.类A是派生类,类b是基类d.类a为派生类或子类,类b为基类、父类或超类(3)c++的继承性允许派生类继承基类的()。
a、部分功能,并允许添加新功能或重新定义基类的功能。
B.部分功能,但不允许添加新功能或重新定义基类的功能。
C.所有特性,并允许添加新特性或重新定义基类的特性。
D.所有特性,但不允许添加新特性或重新定义基类的特性。
(4)派生类的成员函数可以直接访问基类的()成员。
a.所有b.公有和保护c.保护和私有d.私有(5)对于公有继承,基类的公有和保护成员在派生类中将()成员。
a.全部变成公有b.全部变成保护c、 D.保持公共并相应地受到保护(7)对于公共继承,基类中的私有成员将()保留在派生类中。
a.能够直接使用成员名访问b.能够通过成员运算符访问一百三十六c.仍然是基类的私有成员d.变为派生类的私有成员(8)保护继承时,基类的()将成为派生类中的受保护成员。
《基类和派生类的构造顺序》同学们,今天咱们来聊聊基类和派生类的构造顺序,这可是编程里很重要的知识哟!想象一下,基类就像是一个基础的房子框架,派生类呢,就是在这个基础框架上进行装饰和扩展的部分。
当我们创建一个派生类的对象时,先构造的是基类。
为啥呢?因为基类是基础呀,得先把基础打好。
比如说,基类里可能有一些最基本的设置,像房子的地基。
举个例子,假如基类是“动物”,派生类是“猫”。
在创建一只猫的时候,得先有动物的一些基本特征,比如有生命、能活动,然后才有猫的独特特点,像会抓老鼠、爱撒娇。
所以呀,记住这个顺序,先基类后派生类,这样我们在编程的时候就能更清楚啦!《基类和派生类的构造顺序》同学们,咱们来深入了解一下基类和派生类的构造顺序。
先把基类想象成一个大蛋糕的底层,派生类就是在这个底层上面加的各种美味装饰。
当我们要做出一个完整的蛋糕,也就是创建一个派生类对象时,肯定要先有底层的蛋糕坯,这就是基类的构造。
比如说,基类是“交通工具”,派生类是“汽车”。
那得先有交通工具的通用属性,像能移动,然后才有汽车的特别之处,比如有四个轮子、靠汽油驱动。
这个构造顺序很重要哦,如果顺序不对,就像做蛋糕先放装饰再做底层,那可就乱套啦!《基类和派生类的构造顺序》同学们,今天讲讲基类和派生类的构造顺序,这个可有意思啦!把基类当成是一棵大树的树干,派生类就是树干上长出来的树枝和树叶。
当这棵树要长大的时候,肯定得先有树干呀,这就是基类的构造。
比如基类是“水果”,派生类是“苹果”。
先要有水果的共性,像能吃、有营养,然后才有苹果的特点,比如红红的、甜甜的。
要是顺序反了,就像树先长叶子再长树干,那多奇怪呀!所以一定要记住,先构造基类,再构造派生类哟!。
基类派生类构造析构顺序说到基类和派生类的构造和析构顺序,真是个让人又爱又恨的话题。
想象一下,你正在厨房里做饭,锅里的水在烧,突然有人问你:“你觉得先煮面还是先煮菜?”这时候,心里一阵懵圈,不同的顺序会导致完全不同的结果。
基类和派生类的关系也是这么回事,先后顺序可重要了。
你看,基类就像是一棵大树,枝繁叶茂,根深叶茂。
它有着最基本的特征和方法,稳稳当当地立在那儿。
派生类就像是树上的一根树枝,长得漂亮,开着花,结果子,但是没有根的话,树枝随风摇摆,早晚得掉下来。
构造的时候,基类总是先“发声”,先进行构造,之后派生类才能紧接着跟上。
就像开派对,得先把场地布置好,才能让嘉宾入场。
没场地,直接把人扔进去,岂不是乱七八糟?说到这里,估计大家都想问,拆迁的时候呢?这个可有意思了。
拆的时候,派生类要先把自己收拾利索,然后再把基类给拆了。
这就像你在家打扫卫生,先把桌子上的杂物收拾干净,才能好好擦桌面。
要是反过来,桌子还没清理,下面的灰尘全都飞起来,那可就尴尬了。
哦,对了,构造的时候基类先,拆的时候派生类先,这就是所谓的“先大后小”嘛。
这个道理谁都能懂。
就好比买菜,得先把大块头的菜挑好,再慢慢把小的放进篮子里。
要是把小的先放上去,大的那篮子准得翻。
这些顺序的小细节,真是让人感叹不已。
要是顺序搞错了,后果可想而知。
想象一下,你把水壶放在火上,结果忘了开水。
等你回来的时候,水壶已经干烧了,真是让人心痛。
程序里也是一样,如果派生类在基类之前构造,系统会崩溃得比一场地震还厉害,搞得你手忙脚乱,根本来不及反应。
代码报错的那一瞬间,简直就像是中了彩票,但偏偏是个无效的。
再说了,代码里可不能有“急”的事情。
慢工出细活,构造和析构都要稳稳当当。
想象一下,你在给一个新宠物喂食,得先准备好食物和水,再把它放进笼子里。
要是先把它放进去,再给它食物,那小家伙肯定会抗议,甚至闹得不可开交。
怎么样才能记住这个构造和析构的顺序呢?这里有个小技巧,给自己编个口诀,比如“老大先来,后生跟上,收拾残局,细节不能忘”。
5.2 基类和派生类在C++中,当一个类被其他类继承时,被继承的类称为基类(base class)。
继承其他类特性的类称为派生类(derived class)。
从本质上看,基类是具有一个类集合中的公共特性,派生类在继承基类特性的同时可以加入自己独有的特性。
基类与派生类之间反映出下述三种不同的现象:(1)派生类是基类的具体化。
即模拟概念层次,表示“is-a”的关系。
(2)派生类是基类的延迟定义。
可以定义一个抽象基类,定义一些操作,使它们服从一定的协议,但许多可能并未实现,然后定义非抽象的派类,实现抽象基类中定义的行为。
这时派生类不是基类的具体化,而是抽象类的实现。
在JA V A中,有专门的纯虚类,称为接口,其作用就是为不同的类提供一个统一的接口,同时间接实现多继承(JA V A不支持多继承)。
(3)派生类是基类的结合。
当一个派生类有多于一个的基类时,它们组合在一起形成具有所有基类行为的类型。
这时要注意,不要用继承表达聚合关系。
5.2.1 基类与派生类的说明先看一个例子。
[例5.1] 派生类的说明EX5_1.CPP。
继承基类的派生类定义的一般形式:class derived_class_name:access_specifier base_class_name{……};其中access_specifier可以是3个关键字之一:public、private(默认值)或protected。
派生类也称为子类、导出类。
它具有下述特点:(1)可在基类所提供有基础上包含新成员;(2)可在自己类中隐藏基类的任何成员;(3)为新类重新定义基类中的函数;[例5.2] 子类的特点EX5_2.CPP。
5.2.2 派生类的继承权与访问域派生类的继承权如果不能有效在加以限制,就不能按照实际情况表达求解问题的复杂性。
因此访问权限是一个很重要的问题。
(1)对于基类的私有成员,派生类及派生类的使用者无权访问。
(2)对于基类的公有成员,则按派生类的定义,分为三种情况:①私有派生,继承基类的公有成员作为自己的私有成员,这些成员只能被派生类的成员函数访问。
基类与派生类的方法
1、基类与派生类的方法
基类和派生类是面向对象程序设计中的一个基本概念,它们之间是继承关系。
基类指的是父类,派生类指的是子类,基类可以向子类继承属性和方法。
基类的方法:
(1)抽象方法(Abstract Method):由基类定义,由子类实现的方法。
(2)虚方法(Virtual Method):由基类定义,可以被子类重写的方法,也可以被子类不作修改直接使用。
(3)构造函数(Constructor):定义在基类中的函数,用于实例化一个实例。
(4)析构函数(Destructor):定义在基类中的函数,用于释放一个实例所占用的资源。
派生类的方法:
(1)重载(Overloading):派生类可以对基类方法进行重载,也就是派生类中定义的方法可以与基类中同名的方法进行重载。
(2)覆盖(Overriding):派生类可以对基类方法进行覆盖,也就是派生类中定义的方法可以完全替换基类中同名的方法。
(3)构造函数(Constructor):定义在派生类中的函数,用于实例化一个实例。
(4)析构函数(Destructor):定义在派生类中的函数,用于释
放一个实例所占用的资源。
5.2 基类和派生类
在C++中,当一个类被其他类继承时,被继承的类称为基类(base class)。
继承其他类特性的类称为派生类(derived class)。
从本质上看,基类是具有一个类集合中的公共特性,派生类在继承基类特性的同时可以加入自己独有的特性。
基类与派生类之间反映出下述三种不同的现象:
(1)派生类是基类的具体化。
即模拟概念层次,表示“is-a”的关系。
(2)派生类是基类的延迟定义。
可以定义一个抽象基类,定义一些操作,使它们服从一定的协议,但许多可能并未实现,然后定义非抽象的派类,实现抽象基类中定义的行为。
这时派生类不是基类的具体化,而是抽象类的实现。
在JA V A中,有专门的纯虚类,称为接口,其作用就是为不同的类提供一个统一的接口,同时间接实现多继承(JA V A不支持多继承)。
(3)派生类是基类的结合。
当一个派生类有多于一个的基类时,它们组合在一起形成具有所有基类行为的类型。
这时要注意,不要用继承表达聚合关系。
5.2.1 基类与派生类的说明
先看一个例子。
[例5.1] 派生类的说明EX5_1.CPP。
继承基类的派生类定义的一般形式:
class derived_class_name:access_specifier base_class_name
{
……
};
其中access_specifier可以是3个关键字之一:public、private(默认值)或protected。
派生类也称为子类、导出类。
它具有下述特点:
(1)可在基类所提供有基础上包含新成员;
(2)可在自己类中隐藏基类的任何成员;
(3)为新类重新定义基类中的函数;
[例5.2] 子类的特点EX5_2.CPP。
5.2.2 派生类的继承权与访问域
派生类的继承权如果不能有效在加以限制,就不能按照实际情况表达求解问题的复杂性。
因此访问权限是一个很重要的问题。
(1)对于基类的私有成员,派生类及派生类的使用者无权访问。
(2)对于基类的公有成员,则按派生类的定义,分为三种情况:
①私有派生,继承基类的公有成员作为自己的私有成员,这些成员只能被派生类的成员函数访问。
Access_specifier是private或省略。
[例5.3] 私有派生EX5_3.CPP。
②公有派生是基类中所有的公有成员,在派生类中也都是公有的。
它不必一一说明,而在派生类定义时,在基类前加一个public 关键字。
如:
class:public b
{
……
};
③保护派生,基类的公有成员和保护成员在派生类中是保护成员,仅能在派生类的成员中被使用,而不允许派生类的对象使用。
Access_specifier是protected。
表5.1 列出了成员访问控制的各种情况。
(3)派生类对基类成员直接访问问题。
派生类不能访问基类的私有成员,若要访问必须使用基类的接口,即通过基成员函数。
如何直接访问类成员,有两种方法可选:
①在类定义体中增加保护段(protected),将基类私有成员提供派生类访问的部分放置在保护段。
②将需要访问基类私有成员的派生类成员函数声明为基类的友元。
[例5.4] 派生类对基类成员的直接访问EX5_4.CPP。
(?)
(4)访问域的调整规则
使用作用域符(::)可以调整访问域,但要注意其限制条件:
①访问声明只能对变量或函数名,不能说明类型和参数;重载函数只需一个声明即可。
②不能对私有段成员作访问声明,必须保护封装性。
③只能在相应的段(保护或公有段)作访问声明,不能改变所属段。
即基类成员被调整后,在派生类中的访问权限既不能扩大也不能缩小。
基类中的公有成员只能被调整为公有成员,保护成员只能被调整为保护成员,私有成员不可调整。
[例5.5] 访问域的调整EX5_5.CPP。
class base {
public:
int a;
protected:
int b;
private:
int c;
};
class derived:base{
public:
base::a;//correct
base::c;//error
base::b;//error
protected:
base::b;//correct
base::a;//error
base::c;//error
};
若基类和派生类具有同名成员,则基类的该成员被编译器隐藏起来。
若在派生类中调用继承来的被隐蔽的成员,作为访问声明需要明确指定基类类范围;而非同名成员,派生类在使用继承成员时可视为是在该派生类范围,且不必对这些成员重新定义。
5.2.3 派生类的构造函数和析构函数
基类往往有构造函数和析构函数,但创建和结束派生类对象时,如何调用它们,这是下面需要讨论的问题。
(1)执行原则:当基类和派生类都具有构造函数和析构函数时,将按类派生的顺序执行构造函数,而按相反的顺序执行析构函数。
(2)派生类构造函数:当派生类本身需要构造函数,或者是在定义派生类对象时,其相应的基类对象需要调用带参数的构造函数,就必须定义派生类的构造函数。
定义格式如下:
derived_constructor(arg_list):base(arg_list)
{
//body of derived constructor
};
这里建立了一个变量传递链,首先将基类和派生类所需的所有变量都传递给构造函数。
然后,用派生类构造函数的扩展说明形式,将某些变量传递给基类。
[例5.6] 从派生类向基类传递变量EX5_6.CPP。
(3)有关说明
若基类使用缺省构造函数或不带参数的构造函数,则在派生类中定义构造函数时可略去“:base(arg_list)”,此时若派生类还需要初始化,则可不定义构造函数。
派生类是否要定义析构函数与所属基类无关。
若派生类在退出其定义域前需要作释放内存等处理,就需要定义析构函数。
[例5.7] 定义学校人事管理的类及其调用情况显示实例EX5_5.CPP。