• C++虚函数和静态函数调用方式


    简单情况:

    #include<iostream>
    using namespace std;
    class A
    {
    public:
        virtual void foo()
        {
            cout << "virtual void foo()" << endl;
        }
    };
    
    int main()
    {
        //通过对象调用,会当成普通成员函数来看待。
        A a;
        a.foo();
        cout << "---------------------" << endl;
        A *b = new A();
        b->foo();
        //编译器视角
        /*
        ((*(b->vptr))[0])();
        通过虚函数表指针调用
        */
        while (1);
        return 0;
    }

    总结:

    1.如果通过对象调用虚函数,编译器直接找到虚函数的地址。

    2.对于虚函数和成员函数,编译器都会隐式的传入this指针。

    3.对于指针和引用的形式来调用虚函数,编译器走的则是虚函数表的路线。

    4.无论是成员函数还是虚函数,他的地址都是在编译期间就已经确定下来了,接下来就看你怎么去找到这个虚函数的地址,可以直接找,也可以通过虚函数表.

    复杂情况以及静态成员函数的调用形式:

    #include<iostream>
    using namespace std;
    class A
    {
    public:
        virtual void foo()
        {
            cout << "virtual void foo()" << endl;
            //foo2();//如果虚函数里面这么调用还是会通过虚函数表找到虚函数的地址,所以为了效率,通过类调用(因为在函数内部,所以接下来通过类调用这个this指针编译器可以找的到)
            /*
            既然在外部已经进入到该虚函数内部了,说明该对象是生成了的,也就是这个this指针存在了
            所以接下来的A::foo2();调用会成功,如果在main函数中直接调用A::foo1(),肯定失败,因为编译器隐式传进去的形参this根本就找不到
            */
            A::foo2();
        }
        virtual void foo1()
        {
            cout << "virtual void foo1()" << endl;
        }
        static void foo2()
        {
            cout << "virtual void foo2()" << endl;
        }
        void aa()
        {
            cout << "fds" << endl;
        }
        int data = 3;
    };
    int main()
    {
        //如果想让非成员函数像静态成员函数一样被调用。
        ((A*)0)->aa();//前提是函数体中不能用到隐式传进去的0指针。
        /*
        对于成员函数aa(),编译器会隐式的传进去0指针,这个0指针实际上里面并没有保存类A的内容,作用仅仅是用来调用该成员函数,类似于:A*p;
        p->aa();只是用了一种诡异的手法将这两步进行合并,再调用。
        不管是0还是其他的地址,都无所谓,只要用不到那个指针就行,比如 ((A*)899980)->aa();同样也能正常运行,因为前面那个地址仅仅是生成A类型的指针。
        如果写成cout<<((A*)0)->data来打印里面的数据成员就错了,因为0地址里面实际并没有保存真正的类A的内容。
        */
    
        //对于静态的成员函数,它不依赖于类对象,所以编译器并不会给他隐式的传进去this指针。
        //所以可以直接用类成面来调用。
        A::foo2();
    
        //对于虚函数,通过对象调用相当于普通成员函数的调用,用指针和用引用调用则是通过虚函数表来找到对应的虚函数。
        /*A ss;
        //ss.foo();
    
        cout<<"通过虚函数表找到虚函数的地址"<<endl;
        A&p = ss;
        p.foo();
    
        A*p=new A();
        p->foo();
        
        A&cc = *p;
        cc.foo();
        */
    
        /*
        普通的成员函数和虚函数在调用的时候编译器都会隐式的传入this指针,而对于静态函数则例外。
        */
    
        while (1);
        return 0;
    }
  • 相关阅读:
    文件异步上传-ajaxFileUpload
    C# 结构体
    c# nullable类型有什么用
    跨平台理论杂记
    C#类型转换
    C# is as
    C# 类
    CLR的执行模型
    C# 与 LUA 的经验对比
    C#中的Decimal类型
  • 原文地址:https://www.cnblogs.com/SunShine-gzw/p/13179231.html
Copyright © 2020-2023  润新知