C (练习)第8章,继承与派生
- 格式:doc
- 大小:44.00 KB
- 文档页数:7
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去调用这个方法,会优先在自己的方法里去找来调用,如果没有,再去父类里找;也没有的话就报错。
第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.练习题:课后练习题见练习单元。
类是C++中进行数据封装的逻辑单位。
第八章继承与多态习题一.基本概念与基础知识自测题8.1填空题8.1.1 如果类α继承了类β,则类α称为(1)类,而类β称为(2)类。
(3)类的对象可作为(4)类的对象处理,反过来不行,因为(5)。
如果强制转换则要注意(6)。
答案:(1)基类(2)派生类(3)派生类(4)基类(5)派生类有一些新成员(6)只能派生类强制转换为基类8.1.2 当用public继承从基类派生一个类时,基类的public成员成为派生类的(1)成员,protected成员成为派生类的(2)成员,对private成员是(3)。
公有派生可以使其类的(4),所以公有派生是主流。
答案:(1)public成员(2)protected成员(3)不可访问(4)接口不变8.1.3 利用继承能够实现(1)。
这种实现缩短了程序开发的时间,VC++中的(2)很好地体现了这一点。
答案:(1)代码的复用(2)MFC编程8.1.4 一个派生类只有一个直接基类的情况称为(1),而有多个直接基类的情况称为(2)。
继承体现了类的(3)概念,这在MFC中得到了很好表现,MFC中只采用了(4)。
答案:(1)单继承(2)多重继承(3)层次(4)单继承8.1.5 C++中多态性包括两种多态性:(1)和(2)。
前者是通过(3)实现的,而后者是通过(4)和(5)来实现的。
答案:(1)编译时的(2)运行时的(3)函数和运算符的重载(4)类继承关系(5)虚函数8.1.6 在基类中将一个成员函数说明成虚函数后,在其派生类中只要(1)、(2)和(3)完全一样就认为是虚函数,而不必再加关键字(4)。
如有任何不同,则认为是(5)而不是虚函数。
除了非成员函数不能作为虚函数外,(6)、(7)和(8)也不能作为虚函数。
答案:(1)同虚函数名(2)同参数表(3)同返回类型。
如基类中返回基类指针,而派生类中返回派生类指针是允许的(4)virtual(5)重载(6)静态成员函数(7)内联函数(8)构造函数8.1.7 纯虚函数定义时在函数参数表后加(1),它表明程序员对函数(2),其本质是将指向函数体的指针定为(3)。
C++类的继承与派生继承是面向对象程序设计中最重要的机制。
(主要表现为通过一个已有的类能派生出一个新的类)派生其他类的类称为基类或父类。
被派生的新类叫做派生类或子类;派生类不仅继承基类所有的成员而且可以添加新的成员和成员函数,派生类能继承基类的功能。
而且还能添加和改变它的功能。
一种是从基类继承的成员,另一种是添加的成员。
其包括数据成员和成员函数。
单继承派生类的定义格式Class 派生类名:继承方式基类名{派生类新增成员的声明};单继承派生类的声明“:”左右分别为派生类类名和基名:“{}”里面为了类新建的成员派生类的构成(构造函数和析构函数不能被继承,所以在派生类中还需要定义自己的析构函数和构造函数、如果基类含有带参数的构造函数,在派生类的构造函数中先要调用基类的构造函数,使基类中的数据成员首先被初始化)其继承方式有3中:共有继承(public)、私有继承(private)、保护继承(protected)中,某些数据成员和成员函数的访问权限会改变(如公有的成员有可能变成私有成员)但是不管用哪种方式继承都不能将某一成员排除在派生类之外。
派生类还可以定义和基类一模一样的函数(函数名和参数名都一样),覆盖基类中的同名函数。
派生类不仅继承基类的成员,还需要添加自己的成员,从而具有自己的特性,这些成员的定义和基类中的成员定义方式是一样的,可以是共有继承,私有继承、保护继承。
派生类可以向基类对象赋值派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化如果一个函数是基类对象或基类对象的引用,相应的实参可以用子类型对象派生类对象的地址可以赋给指向基类对象的指针变量派生类定义格式Class 派生类:继承方式基类名{Private:派生类中新增加的私有数据成员派生类中新增加的私有成员函数Public:派生类中新增加的公有数据成员派生类中新增加的公有成员函数Protected:派生类中新增加的私有数据成员派生类中新增加的公有成员函数}(派生类的定义和一般类的定义方式很相似,都是以关键字class开头,在类体中都可以包含私有成员函数、公有成员函数、保护成员,其区别在于派生类的定义在派生类名后面用冒号“:”引导继承方式和基类名)。
c 继承与派生练习题C++是一种面向对象的编程语言,其中最重要的概念之一就是继承与派生。
继承允许一个类(称为派生类)从另一个类(称为基类)中继承属性和行为。
这个过程允许我们在派生类中使用基类的成员,同时还可以添加新的成员或者修改基类成员的行为。
在这篇文章中,我们将通过一些练习题来巩固与继承与派生有关的概念和技能。
这些练习题旨在帮助读者更好地理解和应用这些概念。
首先,考虑一下以下的代码段:```cppclass Shape {protected:int width, height;public:Shape(int w, int h) : width(w), height(h) {}virtual int area() = 0;};class Rectangle : public Shape {public:Rectangle(int w, int h) : Shape(w, h) {}int area() override { return width * height; }};class Triangle : public Shape {public:Triangle(int w, int h) : Shape(w, h) {}int area() override { return (width * height) / 2; }};```通过观察上述代码,我们可以看到Shape是一个基类,其派生类有Rectangle和Triangle。
这些派生类通过公有继承的方式继承了Shape类的成员。
另外,注意到Shape类中的区域函数area()被声明为纯虚函数。
接下来,我们通过一些练习题来检验对继承和派生的理解。
练习题1:向Shape的派生类中添加新的成员在给定的代码段中,尝试向Rectangle和Triangle类中添加一个新的成员,例如颜色color。
然后,尝试在main()函数中创建一个Rectangle对象和一个Triangle对象,并打印出它们的属性(包括颜色)和区域。
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、派生类及其应用(1)继承和派生类的概念1)继承:在原有的类(基类、父类)的基础上生成新的类(派生类、子类)的过程。
2)派生类:从基类继承来的类,可以包含父类的全部或部分(虚基类)成员,也可以增加新的成员。
3)派生格式:class <派生类名> : <继承方式><基类名1>, <继承方式><基类名2>, …{<派生类新定义成员>};(2)初始化基类成员、对象成员的方法1)格式类名(参数表0):基类1(参数表1),基类2(参数表2),对象3(参数表3),…{…} //新增成员的初始化2)注意问题①派生成员(从基类继承过来的成员)的初始化:通过派生类的构造函数调用基类的构造函数来完成;——通过基类名调用②对象成员的初始化:通过调用成员对象的构造函数来完成;——通过对象名调用③参数表0中的参数为形参,其它参数表为实参。
3)构造函数和析构函数的调用顺序构造函数的调用顺序是先基类,再对象,最后为派生类;若有多个基类(对象),顺序由派生(说明)的顺序决定,与派生类构造函数中基类(对象)构造函数的调用顺序无关。
析构函数的调用顺序与构造函数的调用顺序正好相反。
4)下列程序构造函数和析构函数的调用顺序是什么?#include <iostream>using namespace std;class A{int a ;public :A(int x) { a=x ; cout<<"调用了A 的构造函数\n" ; }~A( ) {cout<<"调用了A 的析构函数\n" ; }} ;class B{int b ;public :B(int x) { b=x ; cout<<"调用了B 的构造函数\n" ; }~B( ) { cout<<"调用了B 的析构函数\n" ; }} ;class C{int c ;public :C(int x){ c=x ; cout<<"调用了C 的构造函数\n" ; }~C( ) { cout<<"调用了C 的析构函数\n" ; }} ;class D : public A, public B { // 派生的顺序int d ;C c1 ;A a1;public :D(int x, int y, int z, int m) : B (x), A (y),a1(z), c1(m) // 构造函数调用顺序{d=m ; cout<<"调用了D 的构造函数\n" ; }~D( ) { cout<<"调用了D 的析构函数\n" ; }} ;int main( ){ D d1(1, 2, 3, 4) ;return 0;}调用顺序:调用了A 的构造函数调用了B 的构造函数调用了C 的构造函数调用了A 的构造函数调用了D 的构造函数调用了D 的析构函数调用了A 的析构函数调用了C 的析构函数调用了B 的析构函数调用了A 的析构函数十一、运算符重载1、运算符重载通过成员函数或友元函数实现。