• 类和对象(一)this指针详解


    类的定义

    在C语言中,结构体只能定义变量,但是在C++中结构体不仅能定义变量,还能定义函数,此时我们将结构体称为类并且用关键字class表示。

    class className
    {
    // 类体:由成员函数和成员变量组成
    };
    
    • 1
    • 2
    • 3
    • 4

    大体组成如上所示
    eg

    class STu
    {
    	void Print()
    	{
    		cout << "printf" << endl;
    	}
    	int a;
    	int b;
    	int c;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    同时类名称可以直接做类型STu a; STu b;
    :如果函数的声明的定义都在类中的话,那么该函数会被编译器当成内联函数处理,所以一般建议声明和定义分开放。

    访问限定符

    访问限定符,顾名思义,就是限定类中的变量或者函数能否在类外被直接访问,下面是三个访问限定符及其作用。
    在这里插入图片描述
    在这里插入图片描述
    注意: 访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
    注意public默认访问权限为私有,struct默认访问权限为公有(因为struct要兼容C)

    类的封装

    封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
    为什么要有封装?
    在C语言时候,我们自己模拟栈区的实现时,

    struct Stack
    {
    	int* a;
    	int top;
    	int capacity;
    };
    struct Stack  q;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当我们需要需要栈顶元素的时,有时候我们直接写的是q.a[top]或者q.a[top-1],这取决于写程序的人初始化的时候将top初始化成-1还是0,这样的话对使用者就很不方便,而且一旦函数多了,各有各的实现与表示方式,所以C语言是非常自由的,因为它的数据和方法是分离的,主要取决于程序员的素质,为了避免这种情况发生,C++直接将数据和方法直接进行有机结合,对外公开接口,想让用户用到的函数就设置为public,不想让用户看到的函数或者是变量就设置成私有。
    eg:(栈)

    class Stack
    {
    public:
    	void Push(){}//插入弹出我们希望用户使用栈的这个功能所以我们设置为公有,使用户在类外可以直接进行访问
    	void Pop(){}
    	int Top(){}
    private:
    	void Check_capacity() {};//检查是否需要扩容我们不希望用户使用,所以设置成私有
    	
    	int* a;//成员变量我们不希望用户使用的话我们也设置成私有
    	int _top;
    	int _capacity;
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    所以封装本质上是一种管理,想让用户使用的我们直接设置一个公有接口,不想让用户使用的设置为私有,使得用户使用接口方式达到唯一。

    类的作用域

    类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域
    在这里插入图片描述
    上述提到,类中函数,一般还是建议将声明和定义分离,而定义的时候我们要在前面加上该函数时属于哪个类域的。
    eg

    void Stu::Print()
    {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    类的实例化

    用类类型创建对象的过程,称为类的实例化

    1. 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
    2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
      在这里插入图片描述
      理解声明和定义的区别为是否开辟了空间。
      上述提到为变量开辟空间,那么函数呢?看下面的如何计算类的大小

    类大小计算

    在这里插入图片描述

    在这里插入图片描述
    提问
    假如类是这样的:class A3{};
    此时类没有成员变量,此时编译器会给类一个byte占位,表示其存在过。

    This指针

    1,This 指针的引入

    先定义一个日期类

    class Date
    {
    public:
    
    	void Init(int year, int month, int day)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	void Print()
    	{
    		cout << _year << "-" << _month << "-" << _day << endl;
    
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    
    };
    int main()
    {
    
    	Date A;
    	Date B;
    	A.Init(2022, 7, 5);
    	A.Print();
    	B.Init(2022, 7, 4);
    	B.Print();
    	return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    上述中已经讲述了,不同类对象调用的函数都是同一个函数,但是类对象中的成员变量都是不同的,函数是如何知道A调用函数时使用的成员变量就是此时A的变量?
    C++中引入了This指针解决这个问题。

    C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参
    数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该
    指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

    eg
    在这里插入图片描述
    也就是说编译器会自动将对象本身的地址作为一个隐含参数传递给函数,即使我们
    你没有写This指针编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。

    2,This的特点

    1.this指针的类型:类型const
    Date*const this即this指针本身不能被改变,但是其指向的对象可以被改变
    2,只能在“成员函数”的内部使用
    全局函数、静态函数都不能使用this.实际上类中成员函数默认第一个参数都是(Date
    const this)从上述例子中我们也能看出来
    3,this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针所以由此可见,this在成员函数的开始前构造,在成员函数的结束后清除。但是this指针本身和静态函数还是有些区别的,编译器通常会对this指针做一些优化,一般情况由编译器通过ecx寄存器自动传递,不需要用户
    传递因此,this指针的传递效率比较高

    面试题:

    1,this指针存储在哪里
    上述讲述,this指针本质其实是一个成员函数的形参,那么this指针可能是存储在栈区中的,
    2,有些编译器会使用寄存器优化,所有this指针也有可能存放在寄存器中
    下列程序有错吗?

    class A
    {
    public:
    	void PrintA()
    	{
    		cout << _a << endl;
    	}
    	void Show()
    	{
    		cout << "Show()" << endl;
    	}
    private:
    	int _a;
    };
    int main()
    {
    	A* p = nullptr;
    	p->PrintA();
    	p->Show();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    上述程序可以正常运行,因为show函数是放在公共代码区的,并不是类对象中的变量,虽然p是空指针,且传递的是p,然后Show函数中的this指针接受,还是依然能调用函数,并不存在空指针的解引用,所以不会报错,会正常运行
    但如果讲main函数中的内容改一下就会报错
    在这里插入图片描述
    创作不易,还望多多支持,蟹蟹

    在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 相关阅读:
    OCC教学:拓扑
    用友NC6.5 Linux服务器环境部署
    人大金仓分析型数据库外部表(二)
    html中 table的 colspan和rowspan
    Linux命令行解释程序
    金鸣识别网页版:轻松实现表格识别的神器
    【RTOS训练营】I2C和UART知识和预习安排 + 晚课提问
    进程调度算法(拓跋阿秀笔记记录)
    Vue源码解析-简单实现真实DOM转虚拟DOM,虚拟DOM转真实DOM(二)
    设计模式之解释器模式
  • 原文地址:https://blog.csdn.net/cxy_zjt/article/details/125578879