• 【初阶与进阶C++详解】第三篇:类和对象上(类和this指针)


    🏆个人主页企鹅不叫的博客

    ​ 🌈专栏

    ⭐️ 博主码云gitee链接:代码仓库地址

    ⚡若有帮助可以【关注+点赞+收藏】,大家一起进步!

    💙系列文章💙


    【初阶与进阶C++详解】第一篇:C++入门知识必备

    【初阶与进阶C++详解】第二篇:C&&C++互相调用(创建静态库)并保护加密源文件



    💎一、面向对象和面向对象初步认识

    🧡C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
    🧡C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

    💎二、类的引入

    🧡在C++中,结构体内不仅可以定义变量,也可以定义函数 ,C++中用class替代struct

    💎三、类的定义

    🧡class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号 。

    class className
    {
    // 类体:由成员函数和成员变量组成
    }; // 一定要注意后面的分号
    
    • 1
    • 2
    • 3
    • 4

    🧡两种方式定义类

    1.在类里面定义,如果成员函数在内体中定义,会被当作内联函数处理

    class student {
    	public:
    		void showfo() {
    			cout << _name << _sex << _age << endl;
    		}
    	public:
    		char* _name;
    		char* _sex;
    		int _age;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.在类里面声明,在类外面实现,类的定义放在.cpp文件,声明放在.h文件

    class student {
    	public:
    		void showfo();
    	public:
    		char* _name;
    		char* _sex;
    		int _age;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在实现部分要,指定类域,因为函数是属于类域的

    void student:: showfo(){
     //实现
    }
    
    • 1
    • 2
    • 3

    **总结:**一般情况短小函数在类里面直接定义,长一点函数声明和定义要分离

    💎四、类的访问限定符及封装

    🏆4.1访问限定符

    1. public修饰的成员在类外可以直接被访问
    2. protected和private修饰的成员在类外不能直接被访问
    3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
    4. class的默认访问权限为private,struct为public(因为struct要兼容C)

    🏆4.2封装

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

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

    一半设计类,成员数据时私有或者保护的,函数时公有或私有或保护。

    💎五、类的作用域

    在类声明函数,在类外面定义函数需要指定作用域。

    在类里面使用一个成员函数,用到的成员变量不是只向上查找,而是在整个类域里面去找

    void student :: showfo() {
    	cout << _name << _sex << _age << endl;
    }
    
    • 1
    • 2
    • 3

    💎六、类的实例化

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

    1. 用类型创建对象的过程,称为类的实例化 ,并没有分配实际的内存空间来存储它

    2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量 ,可以用下面的student实例出多个对象,他们都是不一样的,但他们调用的是同一个成员函数,所以把成员函数放到公共代码区当中,类只存放成员变量。

      class student {
      	public:
      		void showfo();
      	public:
      		char* _name;
      		char* _sex;
      		int _age;
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 类成员变量只是**声明**,在主函数或者其他函数调用的时候才去定义(因为开辟空间了

    💎七、类对象模型

    🏆7.1如何计算类对象的大小

    1. 类中既有成员变量又有成员函数(只计算成员变量)(没有必要把函数放到类里面存一份,调用的是同一个函数)
    2. 类中只有成员函数(给一个字节)(按道理来说应该是0,但是如果给0,那么地址就没有了为了展位
    3. 空类(给一个字节)(理由和上面一样)

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

    结构体的数据成员,第一个数据成员存放的地址为结构体变量偏移量为0的地址处,其他结构体成员自身对齐时,存放的地址为min{有效对齐值为自身对齐值, 指定对齐值}最小整数倍的地址处,总体对齐时,字节大小是min{所有成员中自身对齐值最大的, 指定对齐值} 的整数倍。

    平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,对于访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

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

    只需要输入#pragma pack(想要指定的对齐参数)

    3.什么是大小端?如何测试大小端?有没有遇到要考虑大小端的场景?

    小端模式:数据的高字节,存放在高地址中,“小端低低”。

    存放0x12345678,高字节0x12,低字节0x78。

    小端模式:
    内存中存放顺序:0x78,0x56,0x34,0x12
    从左往右是低地址往高地址

    大端模式:
    内存中排存放序:0x12,0x34,0x56,0x78
    从左往右是低地址往高地址

    要存放的数据:0x00000004,低字节为:0x04,高字节为:0x00

    小端模式:
    内存中存放顺序:0x04,0x00,0x00,0x00

    大端模式:
    内存中排存放序:0x00,0x00,0x00,0x04

    不同端模式的处理器进行数据传递时必须要考虑端模式的不同。

    💎八、this指针

    🏆8.1this指针的引出

    🧡Print函数两次调用的是同一个,会默认调用关键字this,增加这一个形参,之后也是利用this去访问变量,同时后面访问的d1.Print();也变换成d1.Print(&d1);,实际上访问的是由谁来调用决定,总之就是谁调用就把谁的地址传送过来,this访问的是对象的形参,谁调用就是访问哪个对象,_year等三个都是声明而已,不能直接访问。

    🧡实参和形参不能显示的写出来,我们也不能显示去写,不能在实参和形参使用,但是可以打印this或者在下面代码2的位置使用,this指针本身是const,不能被修改,但是thsi指向的对象可以被修改,同时this可以被初始化为nullptr。
    A.全局函数不具备this指针
    B.static函数不具备this指针
    C.友元函数不具备this指针

    class Date
    {
    public :
    	void Print (Data* const this) //1
    	{
    		cout <<this->_year<< "-" <<this->_month << "-"<<this->_day <<endl;//2
    	}
    	void Init(Data* const this, int year , int month , int day)//3
    	{
    		this->_year = year;  //4
    		this->_month = month;
    		this->_day = day;
    	}
    private :
    	int _year ; // 年
    	int _month ; // 月
    	int _day ; // 日
    };
    int main()
    {
    	Date d1;
         Date d2;
    
    	d1.Init(2022,5,12);
    	d1.Init(2022,5,11);
    
         //d1.Init(&d1, 2022,5,12);//5
    	//d1.Init(&d2, 2022,5,11);
    
    	d1.Print();
    	d2.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

    🏆8.2this指针的特性

    1.下面程序只运行show()函数的话,正常运行,首先空指针的解引用不会报编译错误,其次对象里面只有成员变量,函数不在对象里面,在一个公共的代码区域,p->PrintA()就是找到函数地址,call这个函数的地址(下图show得到自己在公共代码区的地址)image-20220517084901306,p->PrintA()是传参p指针,不会报错。

    2.运行Print()报错,前面传参都一样,但是访问this->_a位置的值,this指针是空指针就会报错。

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

    1.this存在哪里?

    栈,寄存器。this指针把对象的地址作为实参传递过去,this是形参,所以在栈。

    2.this指针可以为空嘛?

    可以初始化为空


  • 相关阅读:
    Python:SM4
    Istio 入门(五):访问控制和流量管理
    车辆车型识别系统python+TensorFlow+Django网页界面+算法模型
    基因检测,如何帮助患者对抗疾病?
    【NeurIPS】解决离线强化学习中的互模拟缺陷,FaceChain团队联合出品
    聊聊Spring Cloud Gateway 动态路由及通过Apollo的实现
    windows mysql安装卸载,多版本mysql方案
    超详细Docker部署SpringBoot+Vue项目(三更博客项目部署)
    【状态估计】将变压器和LSTM与卡尔曼滤波器结合到EM算法中进行状态估计(Python代码实现)
    process information unavailable解决方案
  • 原文地址:https://blog.csdn.net/YQ20210216/article/details/124939039