zoukankan      html  css  js  c++  java
  • 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)))();
    
    }
  • 相关阅读:
    MRC
    navigationcontroller手势翻页和navigationbar
    process monitor教程汇总
    Fixed: The Windows Process Activation Service service terminated with the following error: The system cannot find the file specified
    ObservableCollection 类
    玩转INotifyPropertyChanged和ObservableCollection
    在IIS中寄存服务
    WPF:为什么使用ContentPresenter.ContentSource而不是Content属性?
    正确理解WPF中的TemplatedParent
    Difference between List View and DataGrid in WPF
  • 原文地址:https://www.cnblogs.com/timeObjserver/p/9337813.html
Copyright © 2011-2022 走看看