C++关于继承的那些事

    面向对象编程的主要目的之一是提供可重用的代码,开发大型项目时,已有的代码经过使用并测试,使用它们可以节省时间,也有助于避免在程序中引进错误,另外,必须考虑的细节越少,便能专注于程序的整体策略。
    有很多类库直接给出源代码,可以对其进行修改来满足自己的需要,C++提供了比修改代码更好的方法来扩展和修改类——类继承,它能够从已有的类派生出新的类,而派生类继承了原有类(称为基类)的特征,包括方法。可以通过继承进行的工作如下:
- 可以在已有类的基础上添加功能;
- 可以给类添加数据;
- 可以修改类方法的行为。

简单继承

    从一个类派生出另一个类时,原始类称为基类,继承类称为派生类。public声明表示公有派生,派生类对象包含基类对象,使用公有派生,基类的公有成员将称为派生类的公有成员,基类的私有部分也将称为派生类的一部分,但只能通过基类的公有和保护方法访问,概括说就是
- 派生类对象存储了基类的数据成员(派生类继承了基类的实现);
- 派生类对象可以使用基类的方法(派生类继承了基类的接口)。
    派生类在继承中,需要添加自己的构造函数,也可以根据需要添加额外的数据成员和成员函数。

构造函数和析构函数

    派生类不能直接访问基类的私有成员,而必须通过基类的公有方法进行访问,所以派生类的构造函数 必须使用基类的构造函数。有关派生类构造函数的要点如下:
- 首先创建基类对象;
- 派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数;
- 派生类构造函数应初始化派生类新增的数据成员。
    创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数。基类构造函数负责初始化继承的数据成员,派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类构造函数。
    派生类构造函数可以使用初始化器列表机制传递给基类构造函数,如果没有在成员初始化列表中提供基类构造函数,程序将使用默认的基类构造函数,成员初始化列表只能用于构造函数。
    派生类对象过期时,释放对象的顺序与创建对象的顺序相反,程序将首先调用派生类析构函数,然后再调用基类析构函数。

派生类和基类之间的特殊关系

    派生类和基类之间有些特殊关系:
- 派生类对象可以使用基类的方法,条件是方法不是私有的;
- 基类指针(引用)可以在不进行显式类型转换的情况下指向(引用)派生类对象,但是基类指针或引用只能用于调用基类的方法;
- 对于形参为指向基类的指针(引用)的函数,可以使用基类对象的地址或派生类对象的地址(引用)作为实参。

不能被继承的

    构造函数、析构函数和赋值运算符是不能被继承的,因为这三个方法是针对特定的类的,派生类和基类是两个不同的类,所以他们是不能被继承的。

多态公有继承

    有些时候派生类继承基类的方法,希望同一个方法有不同的行为,方法的行为取决于调用该方法的对象,这种较复杂的行为称为多态——具有多种形态,即通过一个方法的行为随上下文而异。有两种机制可用于实现多态公有继承:
- 在派生类中重新定义基类的方法;
- 引入关键字virtual,使用虚方法。
    如果在派生类中重新定义基类的方法,通常应将基类方法声明为虚的。

virtual

    基类在声明方法时使用关键字virtual,这些方法被称为虚方法。如果方法是通过引用或指针而不是对象调用的,它将确定使用哪一种方法,如果没有关键字virtual,程序将根据引用类型或指针选择方法,如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法。
    虚函数的工作原理如下:
    给每个对象添加一个隐藏成员,隐藏成员中保存了一个指向函数地址数组的指针,这种数组称为虚函数表,其中存储了为类对象进行声明的虚函数的地址。如果派生类提供了虚函数的新定义,该函数表将保存新函数的地址,如果派生类没有重新定义虚函数,该虚函数表将保存函数原始版本的地址。调用虚函数时,程序将查看存储在对象中的虚函数表地址,然后转向相应的函数地址表。
    虚函数的一些注意要点如下:
- 在基类方法的声明中使用关键字virtual可使该方法在基类以及所有的派生类(包括从派生类派生出来的类)中是虚的;
- 如果使用指针对象的引用或指针来调用虚方法,程序将使用为对象类型定义的方法,而不使用为引用或指针类型定义的方法;
- 如果定义的类将被作为基类,则应将那些要在派生类中重新定义的类方法声明为虚的;
- 构造函数不能是虚函数;
- 析构函数应当是虚函数,除非类不用作基类;
- 只有成员函数可以定义为虚函数;
- 如果派生类中没有重新定义函数,将使用该函数的基类版本,如果派生类位于派生链中,则将使用最新的虚函数版本,除非基类版本是隐藏的;
- 重新定义基类的方法不产生重载,派生类重新定义一个版本,则基类版本将被隐藏,派生类对象将无法使用它们,如果要使用重载版本,需要在派生类中重新定义所有版本。

protected

    在类的访问控制中,除了public和private之外,还有protect,关键字protect和private相似,在类外只能用公有类成员来访问protect部分中的类成员,它们的区别是在基类派生出的类中,派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对于外部世界来说,保护成员的行为与私有成员相似,但对于派生类来说,保护成员的行为与公有成员相似。通常,最好对类数据成员采用私有访问控制,不要使用保护访问控制,同时通过基类方法时派生类能够访问基类数据。

抽象基类

    一般来说,派生类都是基类的扩展,当基类的使用不能满足需求时,增加数据和方法来扩展到派生版本,这样的关系一般都是派生类包含基类,如果基类和派生类的关系是相交的,只有部分相同,那么普通的继承就无法实现,这个时候可以使用抽象基类,即表示为相交的部分。抽象基类中的方法可以定义为纯虚函数来表示它的功能未实现,纯虚函数声明的结尾处为=0。
    当类声明中包含纯虚函数时,不能创建该类的对象,包含纯虚函数的类只用作基类,抽象基类必须至少包含一个纯虚函数。
    可以将抽象基类看作是一种必须实施的接口,抽象基类要求具体派生类覆盖其纯虚函数——迫使派生类遵循抽象基类设置的接口规则,在这种情况下,使用抽象基类使得组件开发人员能够制定“接口约定”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值