c++ virtual总结

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

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

// dynamic_poly.h
#include <iostream>
// 公共抽象基类Vehicle
class Vehicle
{
public:
    virtual void run() const = 0;
};
// 派生于Vehicle的具体类Car
class Car: public Vehicle
{
public:
    virtual void run() const
    {
        std::cout << "run a car/n";
    }
};
// 派生于Vehicle的具体类Airplane
class Airplane: public Vehicle
{
public:
    virtual void run() const
    {
        std::cout << "run a airplane/n";
    }
}; 
// dynamic_poly_1.cpp
#include <iostream>
#include <vector>
#include "dynamic_poly.h"
// 通过指针run任何vehicle
void 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

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

http://blog.csdn.net/chief1985/article/details/4755560


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值