C++学习笔记(五)继承和派生(上)

2017-08-01  本文已影响26人  活体检测业余爱好

1、继承的概念及语法

继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)类似。

继承可以理解为一个类从另一个类获取方法(函数)和属性(成员变量)的过程。如果类B继承于类A,那么B就拥有A的方法和属性。被继承的类称为父类或基类,继承的类称为子类或派生类

在上一章中我们例举了不少book类相关的示例,book类中有两个成员变量:title和price,即书的名字和价格。如果此时我们要按照编程语言将这些书进行分类,此时我们需要第三个成员变量language,这个时候我们没有必要重新设计一个全新的类,只需要在book类的基础上加上language属性及其相关的方法即可。

此时就可以将我们需要的codingbook类继承book类就可以得到book类的成员变量及成员函数,继承后在添加需要的language属性和相关的方法。新类codingbook叫做book类的派生类或子类,而原有的book类则称为基类。派生类codingbook除了能够拥有基类book的所有数据成员和成员函数之外,还可以拥有基类没有的language成员变量及其相关成员函数。

由于派生类可以将基类的代码继承过来,无需重新设计,因而继承解决了代码重用的问题,大大提高了软件的开发效率。同时如果这些代码在基类中运行无误,则继承之后到派生类中运行也是不会有问题的。

继承并非只能进行一层,可以是任意层次的。比如codingbook继承自book类,如果我们需要对codingbook类继续添加某一新属性时,同样可以设计一个类继承自codingbook类。

从book类中派生出codingbook类的语法如下例所示。

例1:

为了方便起见,我们先在类定义前声明了一个全局的枚举类型language,用于表示编程语言。book类我们已经很熟悉了,关键是codingbook类的定义。在定义codingbook类时多出了“: public book”,除此之外codingbook类的定义和上一章介绍的类定义方法没有什么差别。其中关键字public指明继承方式属于公有继承,book为被继承的类名。采用公用继承方式,则基类的公有成员变量和成员函数的属性继承到派生类后不发生变化。例如book类的公有的setprice和settitle成员函数继承到codingbook类后,这两个成员变量的属性仍将是public属性。如果在继承过程中不指名继承方式时,编译器系统会默认继承方式为private或protected属性。

在本例中因为已经定义过一个book类,具有book类的基本属性:书名和书的价格。现在需要一个新的类codingbook来描述编程类书籍,为此我们继承book类中的所有成员及成员函数,并新增language属性及相应的操作函数。虽然我们可以继承到book类的私有成员,但是book类的私有成员变量在派生类中我们是无法直接访问的,只能通过间接的方式访问。间接访问则是通过getprice、gettitle、setprice和settitle函数来实现的,因为这些函数在派生类中是public属性的。如下表所示为codingbook类中的所有成员的一览。

2、继承方式

从基类派生出派生类,派生类继承基类的继承方式有三种:public、protected和private。在未指定的情况下编译器会默认继承方式为protected或private方式。

1) public继承方式(mine:可以理解为最多是public)

1. 基类中所有public成员在派生类中为public属性;
2. 基类中所有protected成员在派生类中为protected属性;
3. 基类中所有private成员在派生类中不可访问。

具体示例可以参考上一节中的例1,在此就不再重新举例了。

2) protected继承方式(mine:可以理解为最多是protected)

1. 基类中的所有public成员在派生类中为protected属性;
2. 基类中的所有protected成员在派生类中为protected属性;
3. 基类中的所有private成员在派生类中仍然不可访问。

例1:

本类同样使用上一节中的示例,此时继承方式改为了protected继承,我们再来分析一下codingbook中类成员的属性问题,具体见下表。

3) private继承方式

1. 基类中的所有public成员在派生类中均为private属性;
2. 基类中的所有protected成员在派生类中均为private属性;
3. 基类中的所有private成员在派生类中均不可访问。

mine:
1)综上,基类中private不管子类是已何种方式继承的,都不可以直接访问;
2)除了private,其他的public以及protected都可以被继承过来,可以自己内部直接访问,外部按照权限访问;

例2:

同样,我们来分析一下本例中的codingbook类中所有成员的成员属性,具体见下表。

3、改变基类成员在派生类中的访问属性

使用using声明可以改变基类成员在派生类中的访问属性。我们知道基类的公有成员经过公有继承,在派生类中其属性为public的,但是通过using 声明,我们可以将其改为private或protected属性。(mine:我估计是只可以进行权限缩小)

例1:

通过例1这样的定义,则下面的主函数就会编译错误,在think类对象调用setlang和settitle函数时都不会有问题,因为这两个函数的属性为public,可以访问。唯独setprice函数通过using声明后,由public属性变为了private属性了。

4、名字隐藏

如果派生类中新增一个成员变量,该成员变量与基类中的成员变量同名,则新增的成员变量就会遮蔽从基类中继承过来的成员变量。同理,如果派生类中新增的成员函数与基类中的成员函数同名,则该新增的成员函数就会遮蔽从基类中继承过来的成员函数。

例1:

在本例中定义了一个基类basic,之后通过继承basic类派生出derived类。需要注意的是在basic类中定义了一个成员变量x,该变量是int型,与之对应的成员函数是setx和getx函数。而派生类中同样定义了一个成员变量x,而它是char指针类型,与之对应的成员函数是setx和getx函数。在主函数中,定义了derived类的对象d1,我们在调用setx(char *)函数时,没有问题。接着又调用从基类中继承过来的setx(int)函数,结果编译出错。最后通过类名来调用基类继承过来的setx(int)函数,编译通过。在派生类derived中,setx(char *)与基类继承过来的setx(int)函数同名mine:不管类型相同与否,只管名字是否一样),如此一来,派生类新增的函数setx(char *)遮蔽了从基类继承而来的setx(int)函数,如此一来通过d1.setx(50)调用setx(int)是不成功的,故而出现编译错误,正确的调用方法是通过类名来调用:d1.basic::setx(int)。

从上例中,我们可以看出被遮蔽了的基类的成员变量或成员函数并非是没有继承过来,而仅仅是被派生类的同名成员变量和成员函数给遮蔽了,调用的时候需要用到类名加上域解析操作符

5、间接继承

假设类C继承自类B,类B继承自类A。那么类C中的除了能够继承B类的成员函数和成员变量外,同样也能继承B类继承自A类的所有成员。换言之,类C可以继承来自类A的所有成员。因此继承既可以是直接继承,也可以是间接继承。

例1:

在本例中,先定义了类A,然后通过派生定义了类B,之后再派生出类C。B类和C类都有自己新增的成员变量和成员函数。下面我们将以表格的形式列出类A、B和C的所有成员和成员变量。

从表中我们可以看出类C不仅包含B类的成员,同时还包含了类A中的成员,在表格中我们都这些成员都统一归为继承自类B,而实际上我们也可以将成员变量x及成员函数setx和getx视为间接继承自类A。当然,间接继承所得的成员变量和成员函数,其属性遵循直接继承时的规则。

上一篇下一篇

猜你喜欢

热点阅读