美文网首页
理解虚函数和虚表内存结构

理解虚函数和虚表内存结构

作者: fertilizer | 来源:发表于2017-07-21 10:45 被阅读0次

    2017.7.21

    虚函数是C++多态性的主要组成部分。下面我简单地从单继承分析虚表具体的内存结构。
    先列举一个实例。

    #include <iostream>
    class base {
    public:
        base() {}
        base(int i) {
            this->i = i;
        }
        void print() {
            std::cout << "base print" << std::endl;
        }
        virtual void print_v() {
            std::cout << "base print_v" << std::endl;
        }
    
    private:
        int i;
    };
    
    class derived: public base{
    public:
        derived() {}
        derived(int i, int j): base(i) {
            this->j = j;
        }
        void print() {
            std::cout << "derived print" << std::endl;
        }
        virtual void print_v() {
            std::cout << "derived print_v" << std::endl;
        }
    private:
        int j;
    };
    
    int main( int argc, char *argv[]) {
        base* instance1 = new derived(1, 2);
        instance1->print();
        instance1->print_v();
        return 0;
    }
    

    图1为上述代码的结果图

    图1
    可以发现base类的指针指向派生类对象,调用非虚函数print()时,实际调用了base::print();调用虚函数print_v(),实际调用了derived::print_v(),那么原因是什么呢?首先我们需要了解一下虚表的结构。
    ![图2 base和derived情况](https://img.haomeiwen.com/i1215789/3eddc63b753cc1d6.png?
    ![Uploading IMG_1429_169073.JPG . . .]
    imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    图2 右侧代表虚指针的地址

    虚表属于每一个类,类实例化后对象的首地址存有虚指针,该指针指向虚表的首地址。在上述代码中添加一行代码

    typedef (void)(*fun)(void);
    fun f1 = (fun)*(*((uint64_t **)instance1));
    f1()
    

    输出为

    derived print_v
    
    
    

    这里需要注意,转化类型应该符合该操作系统的内存结构。这里环境是macos sierra

    图3 覆盖的内容

    然而非虚成员函数没有被覆盖,因为成员函数并没有保存在对象中,编译期确定,并静态或动态绑定到对应的对象上。

    所以base类型的指针调用的是继承类的虚函数

    对象实例的虚指针指向对应的虚表,虚表中的虚函数是定义类时就形成的。
    ps: 虚表结构
    包括vptr,RTTI, top offset,接下来我将对多重继承和虚表结构深入理解。

    相关文章

      网友评论

          本文标题:理解虚函数和虚表内存结构

          本文链接:https://www.haomeiwen.com/subject/izvjkxtx.html