继承与派生
- 格式:doc
- 大小:61.00 KB
- 文档页数:6
继承和派生的作用继承和派生是面向对象编程中常用的两个概念,它们在软件开发中起着重要的作用。
继承是指一个类从另一个类继承属性和方法的过程,派生是指在继承的基础上创建新的类的过程。
本文将分别介绍继承和派生的作用。
一、继承的作用1. 代码复用:通过继承,子类可以继承父类的属性和方法,避免了重复编写相同代码的麻烦。
这样可以提高代码的复用性,减少了代码量,提高了开发效率。
2. 继承关系的表达:通过继承,可以清晰地表达类与类之间的关系。
子类继承了父类的属性和方法,说明它们之间有某种联系,有共同的特征或行为。
3. 扩展功能:通过继承,子类可以在父类的基础上新增或修改属性和方法,实现功能的扩展。
这样可以满足不同的需求,增加了代码的灵活性。
4. 统一接口:通过继承,可以定义一个抽象的父类,然后定义多个子类来实现具体的功能。
这样可以实现统一的接口,使代码更加规范和易于管理。
5. 多态性的实现:继承是实现多态性的基础。
子类可以替代父类的位置,通过父类的引用来调用子类的方法。
这样可以实现动态绑定,提高了代码的灵活性和可扩展性。
二、派生的作用1. 创建新的类:派生是在继承的基础上创建新的类的过程。
通过派生,可以基于已有的类创建新的类,并在新的类中添加、修改或重新实现属性和方法。
2. 特化和泛化:通过派生,可以根据具体的需求创建特定的类。
例如,可以从一个通用的动物类派生出狗类和猫类,使它们具有更具体的属性和方法。
同时,也可以从一个具体的类派生出一个更通用的类,使它具有更广泛的适用性。
3. 继承关系的传递:通过派生,可以传递继承关系。
即子类可以继续被其他类所派生,形成更深层次的继承关系。
这样可以实现更复杂的类之间的继承和关联。
4. 重载和重写:通过派生,可以重载和重写父类的方法。
重载是指在子类中定义一个与父类同名但参数列表不同的方法,以实现不同的功能。
重写是指在子类中重新定义一个与父类同名同参数列表的方法,以实现不同的行为。
1. 继承与派生的概念。
1. 继承的概念:继承是面向对象编程中的一个重要概念,它允许我们创建新的类,通过继承现有类的属性和方法来实现代码的重用。
在继承中,有两个类之间的关系,一个是称为父类或基类的类,另一个是称为子类或派生类的类。
子类继承了父类的属性和方法,并且可以根据需要添加自己的额外属性和方法。
继承的概念可以通过一个简单的例子来说明。
假设我们有一个父类叫做An i m a l,它有一个属性n a m e和一个方法s p e a k。
然后我们创建一个子类叫做C a t,它继承了A n i m a l类的属性和方法,并且可以添加自己的额外属性和方法。
通过继承,C a t类可以访问和使用A n i m a l类的属性和方法,同时也可以根据需要添加新的行为。
2.派生的概念:派生是指在继承的过程中创建子类的过程。
通过派生,我们可以基于父类创建新的子类,并且在子类中添加新的属性和方法来实现代码的扩展和重用。
派生可以看作是继承的一种具体实现方式。
派生的概念可以通过继续上面的例子来说明。
假设我们有一个C a t类作为子类,它继承了A n i m a l类作为父类。
在C at类中,我们可以添加额外的属性和方法,如c o l o r和c a t c h M o u s e。
通过派生,C a t类可以获得An i m a l类的属性和方法,并且可以根据需要添加自己的新行为。
3.继承与派生的关系:继承和派生是紧密相关的概念。
继承是指子类从父类继承属性和方法的过程,以实现代码的重用。
而派生是指在继承的过程中创建子类,并且在子类中添加新的属性和方法的过程,以实现代码的扩展。
继承和派生的关系可以通过一个更复杂的例子来说明。
假设我们有一个基类叫做S h a p e,它有一个属性co l o r和一个方法d r a w。
然后我们创建两个子类,一个是C i r c l e,另一个是R e c t a n g l e,它们分别继承了S h a p e类,并且可以根据需要添加自己的额外属性和方法。
继承与派生一、派生的定义假定有一个类A,并根据类A的定义创建一个新类B,类A就称为基类,类B就称称为类A的派生类。
派生类自动包含基类的所有数据成员和成员函数。
这称为派生类继承了基类的数据成员和函数成员。
派生类的定义方式为:class 派生类名:继承方式基类名{……};可以这样认为,派生类的定义包含了基类的定义,也就是派生类的定义是在基类定义之上的扩充。
如图:二、继承与聚合不是所有关系都可以应用为继承关系。
如果要应用为继承,需要进行几个测试。
这里先假定有两个类A和B:●种类测试(包含测试)。
类B是类A的一个子集,即类B包含于类A。
●特殊性测试。
通过种类测试之后,再看类A中是否有不适用于类B的特殊属性。
如果有,需要修改它们的派生关系,再进行派生。
●属于测试。
若类A和B没有通过种类测试,则可以进行属于测试。
如果类B可以表示成类A的一个元素(不是子集),也就是说类B是类A的一部分,那么类A和B应该表示成聚合,而非派生。
举个例子,类Animal表示所有的动物,类Dog表示狗,显然类Dog只是类Animal的一个子集,因此它们可以表示成派生关系(但需要修改)。
又如,类Automobile表示汽车,类Engine表示发动机,显然类Engine是类Automobile的一个元素,它们只能表示成聚合关系。
有一种特殊情况,就是两个类没有通过上面所有的测试,那说明它们的关系不明确。
三、继承方式和基类中访问指定符对继承的影响继承方式和基类中的访问指定符分别可以是public、private和protected中的一种,因此共有3×3=9种组合。
用一个表来说明继承方式和基类访问指定符的作用:①当基类成员是private时,无论继承方式是什么,它在派生类中都是private。
②当基类成员是private时,虽然它会继承为派生类的private成员,但是它不能被派生类的成员函数访问,只能被继承自基类的成员函数访问。
派生与继承的关系,及派生应用中要注意的问题
派生(也称为继承)是面向对象编程中的一个重要概念,它允许一个类(派生类或子类)继承另一个类(基类或父类)的属性和方法。
派生与继承的关系如下:
1. 代码重用:通过继承,派生类可以复用基类的代码,减少代码重复。
2. 扩展性:派生类可以在继承基类的同时添加新的属性和方法,以实现更复杂的功能。
3. 多态性:通过继承,可以实现多态性,即父类指针或引用可以指向子类对象,调用子类的方法。
在派生应用中,需要注意以下几个问题:
1. 封装性:要确保基类的属性在派生类中仍然保持封装性,即不要在派生类中直接访问基类的私有属性。
2. 构造函数:如果基类有构造函数,派生类需要显式调用基类的构造函数,或者在派生类的构造函数中实现与基类构造函数相同的功能。
3. 虚函数和纯虚函数:如果基类中有虚函数或纯虚函数,派生类需要实现这些函数或者声明这些函数为纯虚函数。
4. 访问权限:要确保派生类中的成员函数能够访问基类的公有成员和保护成员,但不能访问基类的私有成员。
5. 覆盖和隐藏:如果基类和派生类中有同名函数,则派生类中的函数会覆盖基类中的函数(也称为重写)。
如果基类中的函数是公有或保护的,而派生类中的函数是私有的,则称为隐藏。
覆盖和隐藏可能会引起一些问题,需要注意区分和处理。
一、类的继承与派生1、三种继承方式:公有、私有、保护不同继承方式的影响主要体现在:●派生类成员对基类成员的访问控制●派生类对象对基类成员的访问控制实际应用中,公有派生用的最为广泛,私有派生相对较少,而保护派生则极少使用2、派生类对基类成员的继承与否是固定的,但程序员可以在派生类中对继承来的成员进行调整,包括修改成员的访问属性和覆盖原有的成员。
(1)修改成员的访问属性:通过不同的继承方式可以改变成员的访问方式(2)覆盖原有的成员:在派生类中定义与基类同名的数据成员或具有相同函数名和参数的成员函数。
(3)在派生类中可以增加新的成员,增加的这部分内容体现了派生类对基类功能的扩展。
【例题:】某IT公司有如下类型的技术人员:程序员、项目经理,他们能完成不同的工作。
对每类技术人员的描述如下:项目经理:员工编号、姓名、所在部门、基本工资、项目提成程序员:员工编号、姓名、所在部门、基本工资、奖金所有的员工都能输出自己的基本信息,包括员工编号、姓名和所在部门。
所有的员工都能计算自己的工资:其中程序员工资等于基本工资加上奖金;项目经理的工资等于基本工资加上项目提成。
要求:用类的继承与派生机制设计描述上述各类技术人员的类。
源代码如下:#include <iostream>#include <string>using namespace std;//定义员工类class Employee{protected: //不能定义成private:int id; //员工编号string name; //姓名string department; //所在部门double base_pay; //基本工资public:Employee(int a,string s1,string s2,double p){id=a;name=s1;department=s2;base_pay=p;}; //构造函数EMPLOYEE(){};void SetID(int i){id=i;}void SetName(string n){name=n;}void SetDepartment(string d){department=d;}void SetBase_pay(double bp){base_pay=bp;}void PrintInfo(); //显示员工基本信息double salary(); //计算员工工资};void Employee::PrintInfo(){cout<<"员工编号:"<<id<<endl;cout<<"姓名:"<<name<<endl;cout<<"员工所在部门:"<<department<<endl;}double Employee::salary(){return base_pay;}//定义程序员类class Programmer:public Employee{private:double bonus;string bm; // 添加新的成员“奖金”public:programmer() { };void SetBonus(double s){bonus=s;}double salary(){return base_pay+bonus;}//覆盖从基类继承的已经不再适用的成员函数/*不能在基类中将base_pay定义成private,否则在这里不能访问,所以要定义成protected*/};Programmer::programmer(int a,string n,string bm,double p,double b):A(),employee(a,n,bm,p){bonus=p;}//定义项目经理类class ProjectManager:public Employee,public A{private:double commission; // 项目提成public:void SetCommission(double c){commission=c;}double salary(){return base_pay+commission;}};void main(){//Employee e;//Programmer e;ProjectManager e;e.SetID(110);e.SetName("john");e.SetDepartment("开发部");e.SetBase_pay(2000);e.SetCommission (1000);e.PrintInfo();cout<<"工资是:"<<e.salary()<<endl;}二、继承关系中成员的访问控制1、公有派生的访问控制基类中所有成员在公有派生类中保持各个成员的原有访问权限。
第7章——继承与派生一、选择题1.在c++中,类之间的继承关系具有( )。
(a) 自反性 (b) 对称性 (c) 传递性 (d) 反对称性2.下列关于类的继承描述中,( )是正确的。
(a) 派生类公有继承基类时,可以访问基类的所有数据成员,调用所有成员函数。
(b) 派生类也是基类,所以它们是等价的。
(c) 派生类对象不会建立基类的私有数据成员,所以不能访问基类的私有数据成员。
(d) 一个基类可以有多个派生类,一个派生类可以有多个基类。
3.当一个派生类公有继承一个基类时,基类中的所有公有成员成为派生类的( )。
(a) public成员(b) private成员(c) protected成员(d) 友员4.当一个派生类私有继承一个基类时,基类中的所有公有成员和保护成员成为派生类的( )。
(a) public成员(b) private成员(c) protected成员(d) 友员5.当一个派生类保护继承一个基类时,基类中的所有公有成员和保护成员成为派生类的( )。
(a) public成员(b) private成员(c) protected成员(d)友员6.不论派生类以何种方式继承基类,都不能直接使用基类的()。
(a) public 成员(b) private成员(c) protected成员(d) 所有成员7.下面描述中,错误的是( )。
(a) 在基类定义的public成员在公有继承的派生类中可见,也能在类外被访问。
(b) 在基类定义的protected成员在私有继承的派生类中可见。
(c) 在基类定义的公有静态成员在私有继承的派生类中可见。
(d) 访问声明可以在公有继承派生类中把基类的public成员声明为private成员。
8.在c++中,可以被派生类继承的函数是( = )。
(a) 成员函数(b)构造函数(c) 析构函数(d)友员函数9.在创建派生类对象时,构造函数的执行顺序是( = )。
(a) 对象成员构造函数—基类构造函数—派生类本身的构造函数(b) 派生类本身的构造函数—基类构造函数—对象成员构造函数(c) 基类构造函数—派生类本身的构造函数—对象成员构造函数(d) 基类构造函数—对象成员构造函数—派生类本身的构造函数10.当不同的类具有相同的间接基类时,( c )。
(a) 各派生类无法按继承路线产生自己的基类版本(b) 为了建立惟一的间接基类版本,应该声明间接基类为虚基类(c) 为了建立惟一的间接基类版本,应该声明派生类虚继承基类(d) 一旦声明虚继承,基类的性质就改变了,不能再定义新的派生类二、阅读下列程序,写出执行结果1.#include<iostream>using namespace std;class Base{ public :void get( int i,int j,int k,int l ){ a = i; b = j; x = k; y = l;}void print(){ cout << "a = "<< a << '\t' << "b = " << b << '\t'<< "x = " << x << '\t' << "y = " << y << endl;}int a, b ;protected :int x, y;};class A : public Base{ public :void get( int i, int j, int k, int l ){ Base obj3;obj3.get( 50, 60, 70, 80 );obj3.print();a = i;b = j; x = k; y = l;u = a + b + obj3.a ; v = y - x + obj3.b;}void print(){ cout << "a = " << a << '\t' << "b = " << b << '\t'<< "x = " << x << '\t' << "y = " << y << endl;cout << "u = " << u << '\t' << "v = " << v << endl;}private:int u, v ;};int main(){ Base obj1;A obj2;obj1.get( 10, 20, 30, 40 );obj2.get( 30, 40, 50, 60 );obj1.print();obj2.print();}2.#include<iostream>using namespace std;class Base1{ public :Base1( int i ) { cout << "调用基类Base1的构造函数:" << i << endl ; } };class Base2{ public:Base2( int j ) { cout << "调用基类Base2的构造函数:" << j << endl ; } };class A : public Base1, public Base2{ public :A( int a, int b, int c, int d ) : Base2(b), Base1(c), b2(a), b1(d) { cout << "调用派生类A的构造函数:" << a+b+c+d << endl; }private :Base1 b1 ;Base2 b2 ;} ;int main(){ A obj( 1, 2, 3, 4 ); }3.#include<iostream>using namespace std ;class A{ public :A( int i, int j ) { a=i; b=j ;}void Add( int x, int y ) { a+=x; b+=y; }void show() { cout<<"("<<a<<")\t("<<b<<")\n"; }private :int a, b ;};class B : public A{ public :B(int i, int j, int m, int n) : A( i, j ),x( m ), y( n ) {}void show() { cout << "(" << x << ")\t(" << y << ")\n" ; }void fun() { Add( 3, 5 ) ; }void ff() { A::show() ; }private :int x, y ;};int main(){ A a( 1, 2 ) ;a.show() ;B b( 3, 4, 5, 6 ) ;b.fun();b.A::show();b.show();b.ff();}(5) (6)(6) (9)4.#include<iostream>using namespace std ;class A{ public :A(const char *s) { cout << s << endl ; }~A(){}};class B : virtual public A{ public :B(const char *s1, const char *s2) : A( s1 ){ cout << s2 << endl ; }};class C : virtual public A{ public :C(const char *s1, const char *s2):A(s1){ cout << s2 << endl ; }};class D : public B, public C{ public :D( const char *s1, const char *s2, const char *s3, const char *s4 ): B( s1, s2 ), C( s1, s3 ), A( s1 ){ cout << s4 << endl ; }};int main(){ D *ptr = new D( "class A", "class B", "class C", "class D" ) ;delete ptr;}三、分析题:2.请按照类成员的访问特性、类层次的继承特点,做出一张表格,总结各种类成员在基类、派生类中的可见性和作用域。
【解答】3.若有以下说明语句:class A{ private : int a1;public : int a2; double x;/*…*/};class B : private A{ private : int b1;public int b2; double x;/*…*/};B b ;对象b将会生成什么数据成员?与继承关系、访问特性、名字有关吗?4.若有以下说明语句:class A { /*…*/ public : void sameFun(); };class B : public A{ /*…*/ public : void sameFun(); };void comFun(){ A a ;B b ;/*…*/}(1) 若在B::sameFun中要调用A::sameFun,语句形式如何?它将在什么对象上操作?(2) 在comFun中可以用什么方式调用A::sameFun和B::sameFun?语句形式如何?它们将可以在什么对象上操作?5.有人定义一个教师类派生一个学生类。