首页 > 代码库 > C++整理——虚函数的使用

C++整理——虚函数的使用

由于在公司内一直是在C语言的开发,大多也是在写业务代码,因此对C++的使用越来越生疏。然而最近在公司玩了一个编码比赛最终折戟让我重新意识到用C++的思想来设计工程的重要性。现在借blog重新梳理一下大学所学。如有疏漏不正之处,敬请指出:)

 

     C++区别于C语言是因为它有三大特性:封装,继承,多态。

     封装要求类内高内聚,类间低耦合。设计类无论在哪个工程里都是一个大学问,至今我也还在摸索TAT....

     继承和多态就是今天主题,

  • 什么是虚函数

  虚函数是指在基类中用virtual标识符标识出来的函数。该函数与基类中其他的函数不同,如果该基类的派生类中有与合格虚函数重名的函数,那么编译器将自动重载成派生类中的重名函数,实现多态。

  talk is cheap, show u the code:

  

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Base
 6 {
 7 public:
 8     void A() { cout << "Base, A()" << endl; };
 9     virtual void B() { cout << "Base, B()" << endl; };
10 };
11 
12 class Derive : public Base
13 {
14 public:
15     void A() { cout << "Derive, A()" << endl; };
16     void B() { cout << "Derive, B()" << endl; };
17 };
18 
19 
20 int main()
21 {
22     Base ex1;
23     Derive ex2;
24         
25         // 用基类的指针指向基类,只能调用基类的方法
26     Base *ptr1 = &ex1;
27 
28         // !只有用基类的指针指向派生类才是有意义的
29     Base *ptr2 = &ex2;
30         
31         // 用派生类的指针只能调用派生类的方法,没有任何意义
32     Derive *ptr3 = &ex2;
33 
34         // 输出基类的A, B
35     ptr1->A();
36     ptr1->B();
37         
38         // 输出基类的A和派生类的B
39     ptr2->A();
40     ptr2->B();
41 
42     return 0;
43 }

 

  • 什么是纯虚函数

  纯虚函数是指在基类中没有具体实现的虚函数,在C++语法中也就表现成 :

   1 virtual void function() = 0; 

     这一类的函数由于在基类中没有实现,对于派生类而言就相当于Java中的一个接口函数,因此派生类必须要实现它。同时,有纯虚函数的基类是不能被创建实例的。对于一个工程的设计者而言,这是一个很好的设计。比如现在我有一个基类Career,我只想让派生类Teacher,Doctor等等去实现这个基类里的function而不想Career被实例化,那么我就可以在Career这个类里加入纯虚函数,将其变成一个接口类,便于工程的管理。

 

  • 什么是虚基类

  虚基类不是有虚函数的基类!

  虚基类不是有虚函数的基类!

  虚基类不是有虚函数的基类!

  重要的事情说三遍!

  由于C++支持多重继承,因此在父类的父类相同时,就很容易发生冲突,产生二义性。因此引入了虚基类的概念。

  我们来看一个经典的菱形继承的问题:

  技术分享

1 class B : public A;
2 class C : public A;
3 class D : public B, public C;

  这种场景下,由于D继承的B,C有着相同的父类,因此如果我们声明D的话,D的内存分配中将会有两份A成员的拷贝,分别是D->B->A和D->C->A。A的访问不明确,将无法编译。

  因此,采用虚基类的声明方式:

1 class B : virtual public A;
2 class C : virtual public A;
3 class D : public B, public C;

  在这种声明方式下,D的内存分配中将只会有一份A成员的拷贝,那么具体是通过D->B->A的路径还是D->C->A的路径访问A呢?答案是,都不通过。在这种继承方式下,必须由派生类(D)对直接基类(B,C)和间接基类(A)直接赋值。在这种情况下,只会执行最终派生类对虚基类的赋值,B和C构造函数中初始化列表里对A的赋值都不会执行。

     最后,虚基类通过三个重要的函数初始化原则保证无二义性:

  (1)虚基类的构造函数在非虚基类的构造函数前调用

  (2)若同一层次调用了多个虚基类,那么他们的调用顺序按声明的顺序来

  (3)若虚基类由非虚基类派生而来,那么先调用基类的构造函数,再调用派生类的构造函数。

   牢记牢记!~ 

 

 

 

           

C++整理——虚函数的使用