C++学习笔记(十四):接口及虚函数

  • c++虚函数

  • c++通过虚函数来实现面向对象中的多态特性。虚函数允许在子类中重写父类的方法。如果在父类中实现一个virtual类型的虚函数,则在子类中可以重写该虚函数。
  • 如果子类继承父类,子类中包含父类同样的方法,但父类中的该方法不是virtual类型的,则会出现如下问题,
  • C++学习笔记(十四):接口及虚函数_第1张图片
  • 上诉代码可正常运行,且执行结果符合预期,但如果在main函数中添加如下代码,程序就不会同预期结果一样进行运行。
  • C++学习笔记(十四):接口及虚函数_第2张图片
  • 如上图红框中部分,我们将一个指向Player的指针赋值给一个Entity指针,之后调用Entity指针的GetName函数,我们预期会调用Player的GetName函数,但实际上调用的却是Entity函数。出现该问题的原因主要是由于我们声明函数的时候该函数通常是在类内部起作用,当调用该方法的时候,会调用属于该类的方法。此时就需要virtual功能。虚函数引入了一种动态联编的方法,通常是通过V表(虚拟函数表)来实现编译。
  • C++学习笔记(十四):接口及虚函数_第3张图片
  • 如上图所示,在父类的GetName函数中添加virtual,程序的执行结果就符合我们的预期。通常,我们会在重写的函数中添加overvide关键字,以此来增加程序的可读性,同时还可以帮助我们检查bug,当子类继承父类的函数名写错时,添加override关键字可将错误检查出来。如下图所示:
  • C++学习笔记(十四):接口及虚函数_第4张图片
  • 虚函数会导致额外的性能开销:一是虚函数需要额外的内存来存储V表;二是当我们每次调用虚函数时,需要遍历这个V表,来确定映射到哪个函数。
  • c++接口(纯虚函数)

  • 纯虚函数本质上和Java中的抽象方法或接口相同。纯虚函数允许我们在基类中定义一个没有实现的函数,然后强制子类去实现。在上述示例中,基类的GetName方法有实现,但实际上基类中该方法的实现没有意义。我们仅仅想要在每个子类中实现GetName方法,获取每个子类独有的name。通过创建一个没有实现的virtua方法来实现上述的需求,该没有实现的virtua方法通常被称为接口。
  • 包含纯虚函数的类不能被实例化,如下图所示,基类的GetName方法为纯虚函数,则在实例化基类时会报错,但子类中实现了GetName,可以正常实例化。换言之,只有在实现了基类的纯虚函数的子类才能被实例化:
  • C++学习笔记(十四):接口及虚函数_第5张图片
  • 接口的主要作用时指定协议,其规范子类,如下图,在Print方法中,我们想传递一个适配多个类的参数,就可以实现一个Printable接口,让所有想调用Print方法的类都继承并实现该接口。接口Printable只是用来规范继承了该接口的子类必须实现GetClassName方法。
  • C++学习笔记(十四):接口及虚函数_第6张图片

你可能感兴趣的:(c++,学习,笔记)