C++虚函数表理解

一,思维模式图

二,代码验证

class A {
public:
    A(int x) {
        fProtected = x;
    }
    float GetFProtected() {
        return fProtected;
    }

public:
    float fpublic = 2.3f; //c++11支持了初始化,但不能使用auto
    string sname = "liqi";
    CMyNumOperator<int>* on = new CMyNumOperator<int>(); //对象也可以

    void TestFunc() {
        cout << "TestFunc" << endl;
    }

    static void StaticTestFunc() {
        cout << "Static-TestFunc" << endl;
    }
    virtual void ToString() {
        cout << "A::ToString" << endl;
    }
protected:
    float fProtected;
    void ProtectedFunc() {
        cout << "PRotectedFunc" << endl;
    }
private:
    void PrivateFunc() {
        cout << "PrivateFunc" << endl;

    }

};

//只管公有继承,不管保护继承和私有继承,意义不大,也太复杂
class B : public A {
public:
    friend void TestProtectedDerive();
    B() :A(1) {}
    void TestForDerive() {
        //公有继承下
        //1,子类可以访问父类的保护成员,不能访问父类的私有成员
        B ob;
        //PrivateFunc(); //error,子类不能访问基类的私有成员
        ProtectedFunc(); //right
        fProtected = 10; //right
        ob.fProtected = 20; //right
    }

    //1,c++中只要基类有相同签名虚函数,则默认为此基类函数也是虚函数[与C#不同],如下情形都成立
    // (1) 函数不声明 virtual
    // (2) 函数声明了 virtual
    // (3) 函数声明了 override
    // (4) 函数声明了 virtual 和 override
    //2,c++中两个关键词作用不同,可以同时存在
    // virtual仅表明函数是虚函数,override是C++11中出现的,明确说明是对基类的重写
    // 它的好处是当函数声明不符合规则时,编译器会报错
    void virtual ToString() override{
        cout << "B::ToString" << endl;
    }
};

void TestVirtualFunctionTable() {
    cout << hex;
     typedef void(*PFUNC)();

    offsetof(A, fpublic); //利用此函数可以算函数布局

    A oa(0);
    B ob;

    //一,通过内存地址修改不可访问的保护变量
    *(float*)((int*)&oa + 1) = 123.4f; //类的第一个变量fpublic赋值,(int*)&oa + 1是跳过虚函数指针
    float fpublic = oa.fpublic;

    //二,通过内存地址调用虚函数
    //A和B的虚函数表地址不一样,也就是说父类和子类各有一张虚函数表
    int* pvptr = (int*)(*((int*)(&oa)));
    cout << "A的虚函数表地址:" << pvptr << endl;    //000DB0D4
    ((void(*)())(*pvptr))();                    //A::ToString

    pvptr = (int*)(*((int*)(&ob)));
    cout << "B的虚函数表地址:" << pvptr << endl; //000DB128
    ((void(*)())(*pvptr))();                    //B::ToString

    cout << "--------------------------" << endl;
    //最简写法
    ((void(*)())(*((int*)*(int*)&oa)))();
    ((void(*)())(*((int*)*(int*)&ob)))();

}

原文地址:https://www.cnblogs.com/timeObjserver/p/9337813.html

时间: 2024-10-19 16:05:32

C++虚函数表理解的相关文章

深入理解C++虚函数表

虚函数表是C++类中存放虚函数的一张表,理解虚函数表对于理解多态很重要. 本次使用的编译器是VS2013,为了简化操作,不用去操作函数指针,我使用到了VS的CL编译选项来查看类的内存布局. CL使用方法: (1)在开始菜单中的vs目录下打开"Visual Studio Tools"目录,找到"VS2013 开发人员命令提示",打开它: (2)将你要编译的文件放到该命令行对应的文件夹中. (3)输入cl "文件名" /d1reportSingleC

从逆向的角度去理解C++虚函数表

很久没有写过文章了,自己一直是做C/C++开发的,我一直认为,作为一个C/C++程序员,如果能够好好学一下汇编和逆向分析,那么对于我们去理解C/C++将会有很大的帮助,因为程序中所有的奥秘都藏在汇编中,很多问题我们从表面上无法看出到底是为什么,只要用逆向工具一分析,很快就能知道其中的所以然来.我们都知道虚函数表是放在类对象的最前面,但是很多人并不知道虚函数表的第一项存放的是什么,下面我用IDA分析一下C++的虚函数调用,从汇编的角度去理解虚函数.此文只适合具有逆向分析基础的读者,如果没有逆向分析

我理解的C++虚函数表

今天拜读了陈皓的C++ 虚函数表解析的文章,感觉对C++的继承和多态又有了点认识,这里写下自己的理解.如果哪里不对的,欢迎指正.如果对于C++虚函数表还没了解的话,请先拜读下陈皓的C++ 虚函数表解析的文章,不然我写的可能你看不懂. 以前一直对于c++多态感觉很神奇,从书上看,多态就是在构造子类对象的时候,通过虚函数,利用父类指针,来调用子类真正的函数.这个解释是正确的,但是它是怎么实现的呢,一直再猜想.以前也知道有虚函数表这件事,也没有仔细理解是什么东东.今天仔细读了陈皓的文章,才明白C++多

对C++虚函数、虚函数表的简单理解

一.虚函数的作用 以一个通用的图形类来了解虚函数的定义,代码如下: #include "stdafx.h" #include <iostream> using namespace std; class Graph { protected: double x; double y; public: Graph(double x,double y) { this->x=x; this->y=y; } virtual void showArea() { cout<

C++学习之虚函数表及调用规范

在支付工具想做社交,即时通讯工具想做app市场,英语字典想做新闻社交的今天,创造这些怪象的公司要求程序员懂得更多几乎是理所当然的,毕竟现在大家什么都想做.这不,正值招聘季,实验室的几位学长也是一直在讨论各种问题,发现对于C++语言而言,问的最多的还是虚函数表和STL. STL的考点至少是实用的,哪怕要求你读过源码,也并不过分,毕竟知根知底才能更好地应用.但要求程序员掌握对象模型着实拎不清,因为这几乎用不到,远没有在设计模式上投入时间实在,或许它们最希望的是拿批发价招语言专家... 我已经近2年没

《COM原理与应用》题外话——C++虚函数表和delete this

delete this看起来非常的奇怪,我记得在<C++ Primer>中提到过delete this,但是我已经忘了在哪了,也一直没有找到(因为没有电子版,所以一直没找到~).<C++ Primer>中提到的是在析构函数中使用delete this会造成析构函数的无限调用,最终造成栈溢出.我也在网上看了一些,很多人觉得不该使用delete this,因为会引起一些问题.但是delete this也挺有用处的,就和goto语句一样,不应该被一棍子打死(goto语句其实怪好用的:-D

c++ 继承类强制转换时的虚函数表工作原理

本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解. #include<iostream> using namespace std; class Base { public: virtual void f() { cout<<"Base::f()"<<endl; } }; class child1:public Base { public: virtual void f() { cout&l

C++中的虚函数表是什么时期建立的?(阿里内推面试题)

虚函数表是在什么时期建立的? 最近参加阿里巴巴公司的内推,面试官问了“虚函数表是在什么时期建立的?”.因为以前对虚函数表的理解不够多,所以就根据程序构建(Build)的四个过程(预编译.编译.汇编和链接),推导出虚函数表应该是在编译器确定的,原因如下: 1)预编译器主要处理那些源代码文件中的以“#”开始的预编译指令,如“#include”.“#define”.很明显这个过程可以排除. 2)汇编器是将编译器生成的汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令.汇编过程相对于

C++虚函数及虚函数表解析

一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Function):基类中没有实现体的虚函数称为纯虚函数(有纯虚函数的基类称为虚基类).C++  “虚函数”的存在是为了实现面向对象中的“多态”,即父类类别的指针(或者引用)指向其子类的实例,然后通过父类的指针(或者引用)调用实际子类的成员函数.通过动态赋值,实现调用不同的子类的成员函数(动态绑定).正是因为这种