day03

一、对象的创建和销毁过程的分析
    1、对象的创建过程:
        a、给对象划分内存空间
        b、执行初始化链表
            1、根据继承表的顺序调用父类的无参构造或者有参构造  
                通过 :父类名(val) 调用父类的有参构造
            2、根据成员变量的定义顺序调用类类型成员的无参构造或者有参构造
                通过 :类类型成员名(val) 调用类类型成员的有参构造
            3、对比其它成员初始化
        c、执行直接的构造函数、可能去申请资源

    2、对象的销毁过程
        a、执行直接的析构函数、可能释放资源
        b、根据类类型成员顺序的逆序,调用它们的析构函数
        c、根据继承表的逆序,调用父类的析构函数
        d、释放对象的内存

二、成员函数是如何区分调用对象 - 使用隐藏的this指针
    1、对象的内存只存储了成员变量,没有存储成员函数指针,相当于所有对象调用同一份成员函数
    2、当对象调用成员函数时,编译器会自动把对象的地址传递给该成员函数,也就是说普通的成员函数中都有一个隐藏的参数,该参数名字叫做this指针,this指针用来接收调用对象的地址
    3、this指针拿到了调用对象的地址后,就可以直接访问该对象的成员,完成区分对象的任务
    4、虽然this指针是隐藏定义的,但是可以显式地使用它,但不要多此一举地显式地定义它

三、常函数
    1、被const修饰了this指针的成员函数,称为常函数
    2、当对象调用成员函数时,编译器会隐式地把对象地址传递给成员函数
    3、当对象被const修饰过具有常属性,就不能直接调用普通的成员函数,因为传递的对象地址也具有常属性,二普通成员函数的this指针参数不具备常属性,所以编译器会报错,C++编译器不允许用带常属性的指针数据给不带常属性的数据赋值
    4、因此需要让成员函数中的this指针也具备常属性,通过const修饰变成常函数,所以const修饰的时this指针,这样就可以让具有常属性的对象能够调用常函数
        返回值 类名::成员函数(参数列表)const    //常函数
        {
           
        }
    5、具有常属性的对象只能调用常函数,常函数中也只能调用常函数,但是不具有常属性的对象都可以调用
    6、同名的成员函数,如果其他参数列表完全相同,但是常属性不同,也可以构成重载(常属性也是参数列表的一部分)
    7、正常来说在常函数中不能修改成员变量,除非该成员在定义时通过mutable修饰

面试问题:
    1、const在C和c++中的相同点、不同点有哪些
        相同点:
            const在C和C++中都用来"显式"地保护数据不被修改
        不同点:
            a、C++编译器会优化const变量的取值过程,哪怕该变量的内存被强行修改也不会改变通过变量访问的数值,这种机制会更安全
            b、在C++中const还可以用于修饰成员函数的this指针,从而定义常函数
    2、一个空的结构体在C和C++中分别占多少字节,为什么
        C中占0字节,C++中占1字节
        在C++结构体中可以定义成员函数,并且默认有四个成员函数(隐藏)[构造、析构、拷贝、赋值],当对象去调用成员函数时,需要传递对象的地址给成员函数,这种机制就要求结构对象需要在内存中有一席之地,所以如果结构没有任何的成员变量,编译器会让结构至少拥有1字节的不适用的内存,让上面这套机制自洽

四、拷贝构造
    拷贝构造就是一种特殊版本的构造函数,格式为
        类名(const 类名& that)
        {
            //执行给每个成员变量进行赋值
        }
        什么时候会调用拷贝构造:
            当使用旧对象给新对象初始化时,会自动调用拷贝构造
            Test t1;            //调用无参构造
            Test t2 = t1;       //调用拷贝构造
            Test t3(t2);        //调用拷贝构造
        拷贝构造的任务:
            负责把旧对象中的成员变量拷贝给新对象,并且编译器默认已经自动生成具有该功能的拷贝构造函数
        什么时候需要显式地拷贝构造
            普通情况下编译器自动生成的拷贝构造完全够用,但当类中有成员是指针类型,且为该指针成员分配了堆内存,如果使用默认自动生成的拷贝构造只会对指针变量的值进行拷贝,此时就会导致两个对象的指针成员指向同一块内存,所以在执行析构函数时会造成重复释放错误。此时应该显式地实现拷贝构造函数
    浅拷贝和深拷贝:
        浅拷贝:
            当类中的成员有指针且分配了堆内存,只拷贝指针变量的值
        深拷贝:
            不拷贝指针变量的值,而是拷贝指针变量指向的内存的内容

五、赋值操作(拷贝赋值、赋值运算符函数)
    任务:就是用一个旧对象给另一个旧对象赋值(两个对象都已经完成创建)
    注意:在C++中会把运算符当函数处理,使用运算符时,会调用运算符函数
    Test t1,t2; //无参构造
    t1 = t2;    //赋值操作函数
    类名& operator=(const 类名& that)
    {

    }
    什么时候需要显式地赋值操作
        普通请求一般不显示写赋值操作
        类似于需要显式地写拷贝构造引用,当需要进行深拷贝时,就要显式的写拷贝构造和赋值操作
    实现赋值操作需要注意的问题:
        虽然赋值操作和拷贝的任务相同,都需要深拷贝,但是环境不同(新对象、旧对象)
        问题1:被赋值的对象的指针已经分配有内存
            a、先释放被赋值者的指针指向的原内存
            b、根据赋值者的赋值重新申请新内存
            c、把赋值者内存的内容深拷贝到新内存中
        问题2:可能出现对象自己给自己赋值的情况
            通过判断this指针和赋值者的地址是否相同,如果相同立即返回*this结束,如果不相同才进行赋值操作
    笔试题:
        实现一个实现类似string类的四个成员函数
        class String
        {

        }
        String str1
posted @   歪爱慕外  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示