• C++入门应该注意的问题(this指针和类对象)


    先说说类

    类有两种定义方式:

    1. 声明和定义全部放在类中,需要注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。

    2. 声明放在.h文件中,类的定义放在.cpp文件中

    类的访问和封装

    问题:C++中struct和class的区别是什么?

    解答:C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。 和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是struct的成员默认访问方式 是private。

    面向对象的三大特性:封装、继承、多态。

    在类和对象阶段,我们只研究类的封装特性,那什么是封装呢?

    封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。 封装本质上是一种管理

    类的实例化:

    1. 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它

    2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

    3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占 用物理空间

    类对象模型

    这里需要注意的是有两点比较重要

    第一是计算类对象的大小

    第二是类对象的存储方式

    解决第一个问题,首先要清楚第二个问题:

    一个类的大小,实际就是该类中”成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。

    接下来计算大小就根据结构体内存对齐的规则来计算,这里可以回想一下C语言内容中提出的几个问题:

    1. 结构体怎么对齐? 为什么要进行内存对齐

    2. 如何让结构体按照指定的对齐参数进行对齐

    3. 如何知道结构体中某个成员相对于结构体起始位置的偏移量

    4. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景

    内存对齐:

    C语言深度解析之六:自定义类型详解(结构体+枚举+联合)_何以过春秋的博客-CSDN博客

    大小端:

    C语言深度解析之一:数据存储_何以过春秋的博客-CSDN博客

    this指针

    说起this指针,其实就是从C++与C语言之间不同的语法特性出发的。

    每一个对象都能通过 this 指针来访问自己的地址:this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。他的类型是* const

    友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。

    同时,静态成员函数也没有this指针。

    为了引入this指针,我们看一个例子

    1. class Date
    2. {
    3. public :
    4. void Display ()
    5. {
    6. cout <<_year<< "-" <<_month << "-"<< _day <
    7. }
    8. //void SetDate(Date* this,int year , int month , int day)
    9. void SetDate(int year , int month , int day)
    10. {
    11. _year = year;
    12. //this->_year = year;
    13. _month = month;
    14. //this->_month = month;
    15. _day = day;
    16. //this->_day = day;
    17. }
    18. private :
    19. int _year ; // 年
    20. int _month ; // 月
    21. int _day ; // 日
    22. };
    23. int main()
    24. {
    25. Date d1;
    26. Date d2;
    27. d1.Init(2021,10,8);
    28. //d1.Init(&d1,2021,10,8);
    29. d2.Init(2022,10,8);
    30. d1.Display();
    31. d2.Display();
    32. return 0;
    33. }

    Date类中有SetDate与Display两个成员函数,函数体中没有关于不同对象的区分,如果创建了d1,d2两个对象,那当d1调用SetDate函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

    所以这里实际上有一个this指针,它指向当前对象,通过它可以访问当前对象的所有成员。

    我们在调用成员函数后,编译器其实会再传一个参数进去,这个参数为当前对象的地址:

    d1.Init(&d1,2021,10,8);
    

    而成员函数本质上是这样:

    1. void SetDate(Date* this,int year , int month , int day)
    2. {
    3. this->_year = year;
    4. this->_month = month;
    5. this->_day = day;
    6. }

    解释完this指针后,来看下面这个程序:

    1. class A
    2. {
    3. public:
    4. void show()
    5. {
    6. cout<<"show()"<
    7. }
    8. void Print()
    9. {
    10. cout<<_a<
    11. }
    12. void PrintA()
    13. {
    14. cout<<"PrintA()"<
    15. }
    16. private:
    17. int _a;
    18. };
    19. int main()
    20. {
    21. A* p = nullptr;
    22. p->show();
    23. p->Print();
    24. p->PrintA();
    25. return 0;
    26. }

    三次调用函数这个程序的结果是什么?

    第一行第三行正常运行,第二场直接崩溃

    这里还引出了一个面试问答:this指针可以为空吗?

    最后谈一个问题:this指针存在哪里?

    不是存在对象中哦

    this指针是形参,形参和函数中的局部变量都是存在函数栈帧里面的,所以this指针是存在栈区的,vs下this指针是通过寄存器ecx传递的

  • 相关阅读:
    逆向-破零64位版本
    【前端】特效开发
    3 Java NIO--Channel
    Acwing 286. 选课(背包类树形DP)
    pg_dump执行流程简单记录
    elasticsearch5.6设置用户名密码
    字符串哈希
    Redis(三) Redis的java客户端
    STM32_ESP8266 连接阿里云 操作图解
    MySQL进阶
  • 原文地址:https://blog.csdn.net/yzy521wjm/article/details/126207829