c++ virtual总结

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

c++是一门面向对象的语言,但是它和c#,java不同,它没有反射机制。没有反射机制使得c++在语言的一些设计方面与其他语言有点不一样,主要体现在智能化方面,许多东西得程序员明确指定,例如本文要讲的virtual关键字。virtual是在运行时才体现的,而c++在运行时无法使用反射来确定当前类的父类是否有此方法,此方法是否被重载等信息,所以必须在写代码时用virtual来明确指明,然后通过编译器做一些特殊处理(也就是使用虚表)。

我们见到virtual最多的地方是在c++里面的多态实现。

  1. // dynamic_poly.h  
  2. #include <iostream>  
  3. // 公共抽象基类Vehicle  
  4. class Vehicle  
  5. {  
  6. public:  
  7.     virtual void run() const = 0;  
  8. };  
  9. // 派生于Vehicle的具体类Car  
  10. class Car: public Vehicle  
  11. {  
  12. public:  
  13.     virtual void run() const  
  14.     {  
  15.         std::cout << "run a car/n";  
  16.     }  
  17. };  
  18. // 派生于Vehicle的具体类Airplane  
  19. class Airplane: public Vehicle  
  20. {  
  21. public:  
  22.     virtual void run() const  
  23.     {  
  24.         std::cout << "run a airplane/n";  
  25.     }  
  26. };   
// dynamic_poly.h#include <iostream>// 公共抽象基类Vehicleclass Vehicle{public:    virtual void run() const = 0;};// 派生于Vehicle的具体类Carclass Car: public Vehicle{public:    virtual void run() const    {        std::cout << "run a car/n";    }};// 派生于Vehicle的具体类Airplaneclass Airplane: public Vehicle{public:    virtual void run() const    {        std::cout << "run a airplane/n";    }};  

  1. // dynamic_poly_1.cpp  
  2. #include <iostream>  
  3. #include <vector>  
  4. #include "dynamic_poly.h"  
  5. // 通过指针run任何vehicle  
  6. void run_vehicle(const Vehicle* vehicle)  
  7. {  
  8.     vehicle->run();            // 根据vehicle的具体类型调用对应的run()  
  9. }  
  10. int main()  
  11. {  
  12.     Car car;  
  13.     Airplane airplane;  
  14.     run_vehicle(&car);         // 调用Car::run()  
  15.     run_vehicle(&airplane);    // 调用Airplane::run()  
  16. }  
// dynamic_poly_1.cpp#include <iostream>#include <vector>#include "dynamic_poly.h"// 通过指针run任何vehiclevoid run_vehicle(const Vehicle* vehicle){    vehicle->run();            // 根据vehicle的具体类型调用对应的run()}int main(){    Car car;    Airplane airplane;    run_vehicle(&car);         // 调用Car::run()    run_vehicle(&airplane);    // 调用Airplane::run()} 

上面的例子来自于http://www.vckbase.com/document/viewdoc/?id=948,这篇文章里面还提到了多态的一些别的例子。关于多态的文章还有孟岩写的一篇http://blog.csdn.net/wuliming_sc/archive/2009/01/31/3855906.aspx,可以看看。

在很多多态的例子中,我们都可以看到将基类的方法声明为纯虚函数(virtual void run() const = 0;),这样可以要求子类必须实现这个方法,同时可以体现面向接口编程。

对于使用了virtual之后编译器会做些什么,我觉得用代码更容易说明问题。下面的例子来自http://www.cppblog.com/zhangyq/archive/2009/06/13/87597.html

1 编译器会为这个类的虚函数添加一个虚表,类似下面的:  
// Pseudo-code (not C++, not C) for a static table defined within file Base.cpp   
// Pretend FunctionPtr is a generic pointer to a generic member function   
// (Remember: this is pseudo-code, not C++ code)   
FunctionPtr Base::__vtable[5] = {   
   &Base::virt0, &Base::virt1, &Base::virt2, &Base::virt3, &Base::virt4   
};

2 然后增加一个指向虚表的指针为每一个类对象,这个指针是隐藏的  
// Your original C++ source code   
class Base {   
public:   
   ...   
   FunctionPtr* __vptr;  ← supplied by the compiler, hidden from the programmer   
   ...   
};   
3 编译器在构造中初始化这个指针   
Base::Base(...arbitrary params...)   
   : __vptr(&Base::__vtable[0])  ← supplied by the compiler, hidden from the programmer   
   ...   
{   
   ...   
}   
在派生类中,它也会增加一个隐藏的虚表,但是它可以overrides基类的虚函数如:   
// Pseudo-code (not C++, not C) for a static table defined within file Der.cpp   
// Pretend FunctionPtr is a generic pointer to a generic member function   
// (Remember: this is pseudo-code, not C++ code)   
FunctionPtr Der::__vtable[5] = {   
   &Der::virt0, &Der::virt1, &Der::virt2, &Base::virt3, &Base::virt4   
};   

从上面的代码我们可以非常容易的划出class的结构图,当然可以用/d1reportSingleClassLayout来显示class的布局图(http://blog.csdn.net/chief1985/archive/2009/10/23/4720191.aspx)。

使用virtual的地方还有虚拟继承和虚拟析构函数。

虚拟继承的例子如下,来自http://blog.csdn.net/wuliming_sc/archive/2009/01/31/3855607.aspx

  1. class Point2d{  
  2. public:  
  3. //...  
  4. protected:  
  5. float _x;  
  6. float _y;  
  7. };  
  8. class Vertex : public virtual Point2d{  
  9. public:  
  10. //...  
  11. protected:  
  12. Vertex *next;  
  13. };  
  14. class Point3d : public virtual Point2d{  
  15. public:  
  16. //...  
  17. protected:  
  18. float _z;  
  19. };  
  20. class Vertex3d: public Vertex, public Point3d{  
  21. public:  
  22. //...  
  23. protected:  
  24. float mumble;  
  25. };  
class Point2d{public://...protected:float _x;float _y;};class Vertex : public virtual Point2d{public://...protected:Vertex *next;};class Point3d : public virtual Point2d{public://...protected:float _z;};class Vertex3d: public Vertex, public Point3d{public://...protected:float mumble;}; 

image

使用虚拟继承一般都是出现了菱形继承(c++允许多重继承),这种情况下若不使用虚拟继承,便会导致以下情况:

1.公共基类子对象的重复创建问题。

2.成员函数的名字冲突问题

3. 数据成员的名字冲突问题

出现虚拟析构函数的地方也是在多态的时候,如果不使用虚拟析构函数,将会导致子类的析构函数没被调用,例子可以参考http://blog.csdn.net/starlee/archive/2006/03/09/619827.aspx

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/tduycc/article/details/83856425