美文网首页
cpp insight

cpp insight

作者: 滩主 | 来源:发表于2019-08-06 22:17 被阅读0次

    new 操作符

    在堆上申请空间,返回首地址至%rax


    cpp也容易被玩坏, 不要在c/c++中秀汇编,作死

    使用%rbx保存类对象地址,若在构造函数里改变%rbx的值,程序crash


    image.png

    类函数调用

    栈上的类对象,函数调用时传入栈地址


    image.png

    构造函数调用

    给我们的编程抽象是类,但是实际都是函数调用、传参


    image.png

    子类赋值到父类

    image.png

    虚函数表

    带有虚函数的类实例化对象时,会添加一个指针指向该类的虚函数表
    there are always 2 pointers leading the vtable: one for the multiple inheritance top pointer and another for RTTI. If your machine and compiler are 64 bits (you really should mention this; it's important), this coincides with 16 bytes of pointers

    image.png

    找到虚函数表位置

    #include <iostream>
    
    class Person
    {
    public:
        virtual void foo()
        {
            std::cout << "foo" << std::endl;
        }
        virtual void bar()
        {
            std::cout << "bar" << std::endl;
        }
    };
    
    typedef void (*FUNC)(void*);
    
    int main()
    {
        Person p;
        p.foo();
    
        long* vptr = (long*)(*((long*)(&p)));
        ((FUNC)(vptr[0]))(&p);
        ((FUNC)(vptr[1]))(&p);
    
        int i = sizeof(Person);
    
        return 0;
    }
    

    类对象调用虚函数和类指针调用虚函数

    image.png
    class Person
    {
    public:
        virtual void foo() {}
        virtual void bar() {}
    };
    
    class Student: public Person
    {
    public:
        int col1;
        virtual void foo() {}
        virtual void bar() {}
    };
    
    
    int main()
    {
        Student p;
    
        p.foo();
        p.bar();
    
    
        auto s = new Student();
        s->foo();
        s->bar();
    
        (*s).foo();
        (*s).bar();
    
        Student &p_ptr = p;
        p_ptr.foo();
        p_ptr.bar();
    }
    

    编译器添加构造函数

    image.png

    禁止对象生成在堆上

    #include <stdlib.h>
    #include <iostream>
    
    class Resource
    {
    };
    
    class NoHashObject
    {
    private:
    
        void* operator new(size_t size)
        {
            return malloc(size) ;
        }
    
        void operator delete(void* pp)
        {
            free(pp) ;
        }
    
    public:
        Resource* ptr ;
        NoHashObject()
        {
            ptr = new Resource() ;
        }
    
        ~NoHashObject()
        {
    
            delete ptr ;
        }
    };
    
    int main()
    {
        // NoHashObject* o = new NoHashObject();
    
        char* tmp = new char[sizeof(NoHashObject)];
    
    
        NoHashObject* o = (NoHashObject*)tmp;
        Resource** r = (Resource**)o;
    
    
        *r = new Resource();
        std::cout << *r << std::endl;
    
        std::cout << o->ptr << std::endl;
    
        delete *r;
        delete tmp;
    
        return 0;
    }
    

    构造函数和析构函数

    当使用new操作符创建一个类类型对象时实际上发生了3个步骤:
    调用函数operator new分配内存
    调用构造函数进行构造对象
    返回构造的对象的指针
    当使用delete操作符释放一个类类型对象时实际上发生了2个步骤:
    调用析构函数进行析构对象
    调用函数operator delete释放内存


    image.png

    函数重载

    在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数


    image.png
    #include <iostream>
    
    class Stu
    {
    public:
        void foo(int)
        {
            std::cout << "Stu::foo(int)" << std::endl;
        }
    };
    
    void foo(const Stu&,int a)
    {
        std::cout<< "foo(const stu&,int)" << std::endl;
    }
    
    void foo(Stu*,int a)
    {
        std::cout<< "foo(stu*,int)" << std::endl;
    }
    void foo(int a,const Stu&)
    {
        std::cout<< "foo(int,const stu&)" << std::endl;
    }
    
    void foo(const Stu&,double a)
    {
        std::cout<< "foo(const stu&,double)" << std::endl;
    }
    int main()
    {
        Stu s;
        Stu& s1 = s;
        foo(&s,100);
        foo(s1,100);
    
        s.foo(100);
        s1.foo(100);
    }
    

    运算符重载

    image.png

    继承的内存布局

    image.png

    vector内存布局

    #include <iostream>
    #include <vector>
    
    
    int main()
    {
        std::vector<int> arr;
    
    
        std::cout << sizeof(std::vector<int>) << std::endl;
    
        for (int i=0;i<10;i++)
        {
            std::cout << arr.size() << " " << arr.capacity() << std::endl;
    
            arr.push_back(i);
    
        }
    
        // &arr 栈上的地址
        // &arr[0] 堆上的Base地址
        // (void*)(*((int **)&arr)) 堆上的Base地址
        std::cout << &arr << " "<< &arr[0] << " " << (void*)(*((int **)&arr)) << std::endl;
    
        std::vector<int> arr1;
    
        arr1 = arr;
    
        std::cout << &arr1 << " "<< &arr1[0] << " " << (void*)(*((int **)&arr1)) << std::endl;
    
        return 0;
    }
    

    都是函数调用

    class Person {
    public:
        int age;
        int weight;
        char name[10];
    
        Person()
        {}
        Person& operator=(Person& p)
        {  
            return p;    
        }
        Person(const Person& p)
        {}
    };
    
    int main()
    {
        Person p;
    
        Person p1 = p;
    
        Person p2;
        p2 = p;
    
        return 0;
    }
    

    const 本意是只读,编译器会做相应优化

    image.png

    内存布局

    class Stu {
    public:
        // int score;
    };
    
    
    int main() {
        Stu s = Stu();
        Stu s1 = s;
        Stu* s2 = new Stu();
        Stu* s3 = &s;
        Stu* s4 = &s1;
    
        Stu s5[10];
        s5[1] = Stu();
    
        Stu* s6 = &s5[1];
        
        return 0;
    }
    
    class Stu {
    public:
        class Person {
    
        };
        Person p;
        int age;
    
        // class Man {
        // public:
        //     virtual void say() {
    
        //     }
        // };
        // Man m;
    };
    
    
    int main()
    {
        Stu s;
        int a = sizeof(s);
        s.age = 10;
        int b = 20;
        
        Stu s1;
        s1.age = 30;
        // s.p = Stu::Person();
        // void* prt = &s.p;
        return 0;
    }
    

    类的数组

    编译器会帮助生成调用构造函数和析构函数


    image.png

    函数传参

    image.png image.png

    使用栈传递参数


    image.png

    返回值

    使用寄存器返回


    image.png image.png image.png

    栈对象复制

    image.png

    异常的实现

    决定类型


    image.png
    image.png
    Advantages:
    
    0-cost for entering try/catch block (as fast as if there was none)
    0-cost for having a throw statement in a function (as long as it is not taken)
    Disadvantage:
    
    Slow in case of exception (10x slower than an if strategy) because the side tables are usually not in cache and then there are expensive computations to run to know which catch clause actually matches (based on RTTI)
    It is a very popular strategy implement on both 32 bits and 64 bits platform for all major compilers... except MSVC 32 bits (if I remember correctly).
    

    运算符呀运算符

    image.png

    lamda

    匿名类的匿名对象,并重载函数调用运算符
    https://hacpai.com/article/1545790136502

    image.png image.png image.png image.png image.png

    lamda

    image.png

    相关文章

      网友评论

          本文标题:cpp insight

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