欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第三章 继承

程序员文章站 2022-03-08 20:34:52
...

第三章 继承

3.1 类的继承与派生

3.1.1 继承与派生的概念

#include<iostream>
using namespace std;
const double PI=3.1415;
class Circle //圆类
{
public:
void SetRadius(double r)
{
    radius = r;
}
double GetRadius() const
{
    return radius;
}
double GetArea() const
{
    return PI*radius*radius;
}
void Print() const
{
    cout<<"半径为"<<radius<<"的圆的面积是"<<GetArea()<<endl;
}
private:
    double radius;
};
class Cylinder
{
	void SetRadius(double r)
	{
		radius = r;
	}
	double GetRadius() const
	{
		return radius;
	}
	void SetHeight(double h)
	{
		height = h;
	}
	double GetHeight() const
	{
		return height;
	}
	double GetArea() const
	{
		return(2 * PI*radius + 2 * PI*radius*height);
	}
	double GetVolume() const
	{
		return(PI*radius*radius*height);
	}
	void print()
	{
		cout << "底半径为" << radius<<"的圆柱体的表面积是"<<getArea()
			<<"体积是"<<GetVolume() << endl;
	}
private:
	double radius;
	double height;
};

  • 在c++中,类的继承是指在一个已有类的基础上设计新类,从而新类直接获得已有类的所有特性(所有成员)

  • 父类/基类–已有类
    派生类/子类–新类

  • 新类可以添加新成员或者改造继承的成员

  • 可以派生多个派生类,每个派生类又可以作为基类继续向下派生

  • 在类“家族”中,所有的下层都直接或间接的继承上层的特征,同时又有区别于发展

  • 最高层是抽象程度最高的,由上至下是一个由一般到普通的过程

交通工具
火车
汽车
飞机
轮船
卡车
小轿车
大客车

3.1.2 派生类的定义

语法格式

class 派生类名:继承方式 基类名1,继承方式 基类名2······
{
    派生类新增成员的定义// 继承方式有三种:public,private,protected
    //如果冒号后只有一个基类名,则为单继承;多个则为多继承
}

3.2 继承方式

private是默认继承方式

3.2.1 公有继承 Public

  • 此种情况下,基类的公有和保护成员在派生类中仍然是公有和保护成员,可有成员函数访问
  • 派生类对象可以访问公有的成员;基类的私有成员,无论是派生类的对象和函数都无法访问

3.2.2 私有继承 Private

  • 私有继承方式下,基类所有的非私有成员在派生类中一律变成派生类的私有成员,派生类只能通过它的成员函数访问,派生类对象不能访问
  • 基类的私有成员依旧只能由基类的成员函数来访问
    总的来说,私有继承之后,基类的非私有成员成为了派生类的私有成员,如果还想进一步派生,这些基类成员就无法在更低层次的派生类中被访问

3.2.3 保护继承 Protected

1.protected 访问权限(重点哦)

  • private和protected都是类外不可访问的权限
  • protected修饰的成员本是私有的,但可以被派生类的成员函数访问

2.protected 继承方式

  • 在此种情况下,基类的非私有成员,在派生类中都变成保护成员,这些成员可以被派生类的成员函数访问,但不能被派生类的对象访问
    protected继承方式可以让我们在类的层次结构中找到数据保护和数据共享之间的结合点
    *比较private与protected
    A为基类
    B为派生类,若B为私有继承,则在C中,则无法继承A中成员
    B为保护继承,则c中仍可继承A的成员

3.3 派生类的构造函数和析构函数

派生类无法继承基类的构造函数和析构函数,需重新定义

3.3.1 派生类的构造函数

  • 派生类的数据成员由所有基类的数据成员与派生类新增的数据成员组成
    因此 构造派生类的对象时,必须对这些数据成员进行初始化

*派生类的构造函数
功能1:以合适的初值作为参数,隐含调用基类的构造函数———初始化基类的数据成员
功能2:对新增的数据成员初始化

派生类名(参数表):基类名(参数表1),···,基类名n(参数表n)
{
    派生类新增成员的初始化
                    //初始化顺序:先调用基类构造函数初始化基类数据成员-->如果有子对象,随后进行子对象的初始化-->最后初始化新增成员函数
                    //if派生类的基类也是一个派生类,则每个派生类只负责其直接基类的构造函数的初始化,依次上溯
                    //详情见P91代码示例
}

3.3.2 析构函数

析构函数依旧需要自己定义

  • 在执行派生类的析构函数时,基类的析构函数也被自动调用
  • 析构顺序:调用派生类的析构函数,析构派生类对象的新增部分——>若有子对象,就析构子对象–>最后调用基类的析构函数析构基类部分

3.4 多继承

3.4.1 多继承的声明

一个字类可以拥有多个父类

多继承可以看作多个单继承的组合

class 派生类名:继承方式 基类名1,继承方式 基类名2·····

3.4.2 多继承的构造函数

多继承中,当派生类的构造函数需要初始化多个基类的数据成员时,应按照声明顺序,逐一提供参数,并调用基类的构造函数来初始化

3.4.3 多继承中的二义性问题

常见问题:从不同基类继承来的成员同名而造成的二义性问题

3.5 虚基类

3.5.1 虚基类的作用

虚基类是消除多继承中的二义性的一种简便而有效的方法
*产生原因:如果在多条继承路径上有一个公共基类,那么由他派生出的两条(及以上)路径的汇合处的派生类会存在两套(及以上)继承自该公共基类的同名数据成员
这种情况下,可以将公共基类设为虚基类,来保证成员在派生路径的唯一性

虚基类由关键字virtual标识
class 派生类名:virtual 继承方式 基类名

3.5.2 虚基类的初始化

虚基类的初始化在语法上和一般基类一样,只是调用顺序略有不同
顺序如下:
1.虚基类的构造函数在非虚基类之前调用
2.若同一层次中包含多个虚基类,则按他们的声明顺序调用
3.若虚基类由非虚基类派生而来,要先调用更高级别基类的构造函数,在1.和2.
具体见课本例子P102

3.6 组合类

3.6.1 组合类的概念

类的组合:一个类的数据成员中含有一个或多个类对象,拥有这样结构的类就是组合类,这种以数据成员身份出现的类对象就叫子对象
*组合类创建的对象和子对象之间是一种“整体与部件”的关系,也是一种“拥有(has a)”关系
一般把子对象的访问权限设为私有

3.6.2 组合类中的构造函数

定义格式

类名::类名(形参表):基类1(形参表1),...,基类n(形参表n),子对象1(形参表1),...,子对象n(形参表n)
{
本类新增数据成员的初始化;
}

系统对构造函数的调用顺序:
1.基类的构造函数,初始化基类的数据成员
2.子对象所在类的构造函数
3.本类的构造函数
析构顺序与之相反