C++ 继承知识点总结

C++继承知识点总结

  • 公有继承时,基类的公有成员变量会成为派生类的公有成员,基类的私有成员成为派生类的私有成员,基类的私有成员派生类只能通过继承的基类的公有方法或者保护方法访问
  • 公有继承是is-a的关系,任何可以用基类完成的,都应该可以用派生类完成。如水果和苹果的关系。
  • 派生类需要自己的构造函数,在构造派生类对象之前(准确来说是在进入派生类的构造函数函数体之前),派生类首先会调用基类的构造函数来初始化基类的私有变量,通过初始化列表实现。总的来说,基类的构造函数是用来初始化继承的那部分成员变量,派生类的构造函数用来初始化添加的那部分成员变量。
  • 如果没有在初始化列表中显式调用基类的构造函数,程序会自动调用基类的默认构造函数(所以要保证基类提供了默认构造函数
  • 由于基类的私有成员只能通过基类的公有或者保护方法访问,但是当派生类要访问基类的私有成员时,C++给出解决方法:
    • 构造函数用成员初始化列表的形式调用基类构造函数(成员初始化列表只能用在构造函数中)
    • 非构造函数可以显式调用基类的方法。如果子类中没有再次重写该方法,则不需要加ClassName::,否则需要显式调用。

  • 基类的指针和引用可以直接指向或引用派生类对象,但是这个指针或者对象只能调用基类的方法,反之用派生类指针指向基类则不成立。这是因为派生类中包含基类的方法,因此可以用基类的指针或引用去调用派生类中的基类方法,但是当派生类指针指向基类时,基类中不存在派生类中添加的方法,所以不成立。
  • 虚函数一般用在需要在派生类中重载的函数前(virtual),派生类的函数签名必须保持一致,虚函数特点是可以用相同的基类指针调用不同层级的派生类的实现
  • virtual析构函数,当使用delete BaseClassPtr删除基类指向的内存时,如果BaseClassPtr指向的是派生类,则基类析构函数必须要加virtual,否则只能该操作调用基类的析构函数。当在派生类中用new的时候一定注意
  • 将源代码中的函数调用解释为执行特定函数代码块称为绑定函数名(binding),进一步可分为:
    • 静态绑定(static binding):在编译的时候就确定会调用的是哪一个函数,
    • 动态绑定(dynamic binding):在执行的时候才能确定会调用哪个函数(编译器并不知道之后user会让指针指向哪一类)
  • 基类的指针或者引用用来表示派生类叫做上映(upcasting)
  • 虚函数的实现:编译器在处理虚函数的时候,在每个类中会添加一个指向虚表的指针。虚表其实就是存储类中虚函数地址的一个数组派生类同样包含一个这样的指针,但是这个指针指向的表和基类的不同。如果派生类提供了一个虚函数的新的定义,那么派生类的虚表中就会保存这个新定义的函数的地址;如果没有提供新的定义,那么虚表保存的还是原来的那个函数的地址;如果派生类中新添加了一个虚函数,那么这个虚函数地址会被添加进虚表中。
  • 每个类都额外需要空间来保存函数地址;编译器会给每个类都创建一个虚表;每次调用函数的时候,编译器都会到表中查询对应的函数地址
  • 构造函数不能是虚函数,简单理解就是函数名都不一样当然不可能是同一个函数的多态,实际上是因为派生类的构造函数会调用基类的构造函数,这不是一个继承的关系
  • 除非该类不会被用为一个基类,否则析构函数必须是虚函数,尤其是当派生类的构造函数多用了new分配空间时。基类必须显示声明一个虚的析构函数,尽管这个虚函数什么也没做
  • 友元函数不能是虚函数,因为它不是函数成员,只有成员函数才能声明为虚函数
  • 如果派生类A是派生链上的一部分(指派生类继承的基类B实际上也是由基类的基类C派生而来),且派生类没有重新定义该函数的函数体,虚函数调用的实际是这条链上最近的定义类中的那个函数
  • 如果派生类重新定义了虚函数,但是这个重新定义的虚函数它的函数签名和基类的不一致,这个时候派生类定义的方法会隐藏掉所有基类(基类的基类)的同名方法(派生类就不能用了),所以如果要重载基类的方法,派生类中重新定义的方法的函数签名必须和基类的保持一致,否则会出错
  • 有一种特殊情况函数签名可以存在差异,但也只是返回值允许差异,函数参数不允许:返回值是指向基类的引用或者指针时,派生类重载的方法可以用派生类的指针或者引用来代替
  • 如果基类中定义了同一个函数名的虚函数的多个版本(不同的参数),那么继承的函数也需要提供所有这些对应版本的重新定义。如果只提供一个版本的话,会导致基类的其它版本被覆盖。

  • protected关键字:对类外来说,protected作用域的成员就和private一样,只能通过public中的方法访问,和private区别在于,如果出现继承,基类中的protected成员在派生类中是可以直接访问的,但是private成员必须通过基类的公有方法访问。protected一般用来修饰成员函数
  • Abstract Base Class(ABC)抽象基类提供最基本的变量和方法接口,它只作为基类被继承,不能实例化,所以必须至少包含一个纯虚函数
  • 纯虚函数的实现是在函数声明后面加= 0如果一个类中存在纯虚函数,那么这个类不能实例化,换句话说,类中函数申明中包含= 0就是告诉这个类是ABC抽象类
  • 纯虚函数的设计需要综合考虑整个问题的建模和不同类之间的交互

  • 继承和动态内存分配:假设基类构造函数使用了new进行动态内存分配,且定义好了拷贝构造函数,重载了赋值符,并且提供了虚的析构函数。此时继承了该基类的派生类的相关函数的定义情况:
    1. 如果派生类没有新添加动态内存的操作:则不需要定义析构函数,因为派生类的默认析构函数会首先释放类中的自动变量,然后调用基类的析构函数,释放掉动态内存;也不需要定义拷贝构造函数,因为默认的拷贝构造函数会进行新增成员的值的逐个拷贝,然后对与基类部分会显式调用基类的拷贝构造函数。赋值符号也不需要重载,原因和之前一样
    2. 如果派生类新添加了动态内存:需要定义派生类的析构函数,但是派生类的析构函数只负责释放掉新增的动态内存,基类的动态内存由C++机制自动调用基类的析构函数释放;拷贝构造函数也是需要定义新添加的动态内存部分的值的拷贝,但是基类部分的值的拷贝需要在初始化列表中显式调用基类的拷贝构造函数;重载赋值符号时,需要在函数体中显式调用基类的拷贝构造函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值