虚函数内部原理的解析

什么是虚函数

  简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。下面来看一段简单的代码

  class A{

  public:

  void print(){ cout<<"This is A"<<endl;}

  };

  class B:public A{

  public:

  void print(){ cout<<"This is B"<<endl;}

  };

  int main(){ //为了在以后便于区分,我这段main()代码叫做main1

  A a;

  B b;

  a.print();

  b.print();

  }

  通过class A和class B的print()这个接口,可以看出这两个class因个体的差异而采用了不同的策略,输出的结果也是我们预料中的,分别是This is A和This is B。但这是否真正做到了多态性呢?No,多态还有个关键之处就是一切用指向基类指针或引用来操作对象。那现在就把main()处的代码改一改。

  int main(){ //main2

  A a;

  B b;

  A* p1=&a;

  A* p2=&b;

  p1->print();

  p2->print();

  }

  运行一下看看结果,哟呵,蓦然回首,结果却是两个This is A。问题来了,p2明明指向的是class B的对象但却是调用的class A的print()函数,这不是我们所期望的结果,那么解决这个问题就需要用到虚函数

  class A{

  public:

  virtual void print(){ cout<<"This is A"<<endl;} //现在成了虚函数了

  };

  class B:public A{

  public:

  void print(){ cout<<"This is B"<<endl;} //这里需要在前面加上关键字virtual吗?

  };

  毫无疑问,class A的成员函数print()已经成了虚函数,那么class B的print()成了虚函数了吗?回答是Yes,我们只需在把基类的成员函数设为virtual,其派生类的相应的函数也会自动变为虚函数。所以,class B的print()也成了虚函数。那么对于在派生类的相应函数前是否需要用virtual关键字修饰,那就是你自己的问题了。

  现在重新运行main2的代码,这样输出的结果就是This is A和This is B了。

现在来消化一下,我作个简单的总结,指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。

 

 

对于A* p2=&b;上面分了2中情况,一是不加virtual就是B.PRINT()覆盖A.PRINT(),加virtual就是B.PRINT()重写A.PRINT(),那么同样是b->Print()。

A类型对象指针p2在调用Print()的时候,会从继承链中依次查找如果找到了,就不再向上了。
    没有加virtual的时候,即A中的PRINT()在A* p2=&b的时候没有重写,所以就访问了a类的print。加virtual的时候,A* p2=&b这段override了 ,A的print()会被B.PRINT()重写掉,A.PRINT()会在A* p2=&b这时候失去内存空间,那么b->Print()查找到的就是B.Print()这个重写后的函数了。

posted @ 2012-11-16 08:42  FiberHomer  阅读(328)  评论(0编辑  收藏  举报