虚函数表剖析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/isunbin/article/details/88891582

为了实现C++的多态,C++使用了一种动态绑定的技术。这个技术的核心是虚函数表(下文简称虚表)。本文介绍虚函数表是如何实现动态绑定的。

C++多态实现的原理:

  •  当类中声明虚函数时,编译器会在类中生成一个虚函数表
  • 虚函数表是一个存储成员函数地址的数据结构
  • 虚函数表是由编译器自动生成与维护的
  •  virtual成员函数会被编译器放入虚函数表中
  • 存在虚函数表时,每个对象中都有一个指向虚函数表的指针

二、类的虚表

每个包含了虚函数的类都包含一个虚表。 
我们知道,当一个类(A)继承另一个类(B)时,类A会继承类B的函数的调用权。所以如果一个基类包含了虚函数,那么其继承类也可调用这些虚函数,换句话说,一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。

我们来看以下的代码。类A包含虚函数vfunc1,vfunc2,由于类A包含虚函数,故类A拥有一个虚表。

class A {
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};

虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针。需要指出的是,普通的函数即非虚函数,其调用并不需要经过虚表,所以虚表的元素并不包括普通函数的函数指针。 
虚表内的条目,即虚函数指针的赋值发生在编译器的编译阶段,也就是说在代码的编译阶段,虚表就可以构造出来了。

三、虚表指针

虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可。同一个类的所有对象都使用同一个虚表。 
为了指定对象的虚表,每个对象的内部包含一个虚表的指针,来指向自己所使用的虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,*__vptr,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。

上面指出,一个继承类的基类如果包含虚函数,那个这个继承类也有拥有自己的虚表,故这个继承类的对象也包含一个虚表指针,用来指向它的虚

四、动态绑定

class A 
{
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};

class B : public A 
{
public:
    virtual void vfunc1();
    void func1();
private:
    int m_data3;
};

class C: public B 
{
public:
    virtual void vfunc2();
    void func2();
private:
    int m_data1, m_data4;
};

类A是基类,类B继承类A,类C又继承类B。类A,类B,类C,其对象模型如下图3所示。

class A 
{
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};

class B : public A 
{
public:
    virtual void vfunc1();
    void func1();
private:
    int m_data3;
};

class C: public B 
{
public:
    virtual void vfunc2();
    void func2();
private:
    int m_data1, m_data4;
};

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <list>
using namespace std;

template <typename Sequence>
inline ostream& println(Sequence const& seq)
{
    for (auto const& elem : seq)
        cout << elem << " ";
    cout << endl;
    return cout;
}

inline bool is_shorter(std::string const& lhs, std::string const& rhs)
{
    return  lhs.size() < rhs.size();
}

void elimdups(vector<string> &vs)
{
    sort(vs.begin(), vs.end());
    auto new_end = unique(vs.begin(), vs.end());
    vs.erase(new_end, vs.end());
}

int main()
{
    vector<string> v{ "1234", "1234", "1234", "Hi", "alan", "wang" };
    elimdups(v);
    stable_sort(v.begin(), v.end(), is_shorter);
    cout << "ex10.11 :\n";
    println(v);
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/isunbin/article/details/88891582