您的位置:首页 > 汽车 > 新车 > C++类和对象(上) 需c基础 超详细!!!

C++类和对象(上) 需c基础 超详细!!!

2024/12/23 2:57:51 来源:https://blog.csdn.net/weixin_70873145/article/details/142034463  浏览:    关键词:C++类和对象(上) 需c基础 超详细!!!

在最开始,总共分为上 、中、 下三章,循序渐进一点点理解;如果是有些部分看不懂可以去看看—>入门篇c++

1. 类的定义

  1. class是类的关键字,jojo为类的名字,{ } 内是类的主体,结束符号后面的分号一定不能省略。类体中的内容是成员:类中的变量为类的属性或者成员变量,类中的函数为类的方法或者叫成员函数;
  2. 最开始可以理解和C语言的stack很相似;了解完基础信息,再来讲讲 访问限定符,一便更好的了解类
#include <iostream>
#include <stdlib.h>
using namespace std;
class jojo
{
public:void STPush(){}void Top(){}// 成员函数       void Init(int n = 4){int* array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc 申请空间失败");return;}capacity = n;top = 0;}
private://成员变量int* a;int top;int capacity;void Pop(){}
}; // 此处分号不能省略
int main()
{jojo st;st.Top();st.Init();//st.Pop(); //访问权限不够,和访问结构体的方法类似return 0;
}

3.为了区分成员变量,会加上一些特殊符号告诉你这个是成员变量,一般都会加上 " _ " 或者 m开头的或者其他的,在C++中并没有明确规定,都是看公司的或者个人喜好,不过java里面是有明确命名规定的

class Data
{
public:void time(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
int main()
{jojo st;st.Top();st.Init();//st.Pop(); //访问权限不够,和访问结构体的方法类似Data t;t.time(2024, 7, 21);return 0;
}
  1. C++中的struct也可以用来定义类了,C++继续兼容C语言的用法,同时struct升级成为类,最主要的变化是struct中可以定义函数,不过更加推荐用class
    1. 如果要访问类里面的成员函数需要Data_2::time(int year, int month, int day)才可以使用成员函数,只是声明和定义分离了;
    2. 如果不指定类域Data_2 :: 这个,它去全局找就会找不到,本质上{}括起来的都会形成一个域
    3. C++,类名代表类型,直接可以表示类型可以不用向C语言一样重新取名
  2. 类里面声明的time函数,写在外面;叫做声明和定义的分离,time成员函数会受到类域影响

struct Data_2
{
public:void time(int year, int month, int day);
private:int _year;int _month;int _day;
};//类里面声明的time函数,写在外面;叫做声明和定义的分离,time成员函数会受到类域影响
void Data_2::time(int year, int month, int day)  
{_year = year;_month = month;_day = day;
}//C语言
typedef struct Queue
{int val;struct Queue* next; // C语言要这么写,是因为不知道类型
}Qu;// typedef ,是给他重新取一个名字,不用写冗长的typedef struct Queue,C++ 的Queue直接可以表示类型// CPP 
struct Queue  //C++,类名代表类型
{int val;Queue* next;//这里指向的下一个节点不用在写struct了,直接和struct Queue* next;效果一样
};

1.1. 类定义格式

  1. class是类的关键字,jojo为类的名字,{ } 内是类的主体,结束符号后面的分号一定不能省略。类体中的内容是成员:类中的变量为类的属性或者成员变量,类中的函数为类的方法或者叫成员函数;
  2. 最开始可以理解和C语言的stack很相似;了解完基础信息,再来讲讲 访问限定符,一便更好的了解类

#include <iostream>
#include <stdlib.h>
using namespace std;
class jojo
{
public:void STPush(){}void Top(){}// 成员函数       void Init(int n = 4){int* array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc 申请空间失败");return;}capacity = n;top = 0;}
private://成员变量int* a;int top;int capacity;void Pop(){}
};
int main()
{jojo st;st.Top();//这里是通" . ",可以访问到该对象的函数st.Init();//st.Pop(); //访问权限不够,和访问结构体的方法类似return 0;
}

3.为了区分成员变量,会加上一些特殊符号,告诉你这个是成员变量,一般都会加上 " _ " 或者 m开头的或者其他的,在C++中并没有明确规定,都是看公司的或者个人喜好,不过java里面是有明确命名规定的

class Data
{
public:void time(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
int main()
{jojo st;st.Top();st.Init();//st.Pop(); //访问权限不够,和访问结构体的方法类似Data t;t.time(2024, 7, 21);return 0;
}
  1. C++中的struct也可以用来定义类了,C++继续兼容C语言的用法,同时struct升级成为类,最主要的变化是struct中可以定义函数,不过更加推荐用class
    1. 如果要访问类里面的成员函数需要Data_2::time(int year, int month, int day)才可以使用成员函数,只是声明和定义分离了;
    2. 如果不指定类域Data_2 :: 这个,它去全局找就会找不到,本质上{}括起来的都会形成一个域
    3. C++,类名代表类型,直接可以表示类型可以不用向C语言一样重新取名
struct Data_2
{
public:void time(int year, int month, int day);
private:int _year;int _month;int _day;
};
void Data_2::time(int year, int month, int day)
{_year = year;_month = month;_day = day;
}//C语言
typedef struct Queue
{int val;struct Queue* next; // C语言要这么写,是因为不知道类型
}Qu;// typedef ,是给他重新取一个名字,不用写冗长的typedef struct Queue,C++ 的Queue直接可以表示类型// CPP 
struct Queue  //C++,类名代表类型
{int val;Queue* next;//这里指向的下一个节点不用在写struct了,直接和struct Queue* next;效果一样
};
  1. 定义在类里面的成员函数都是默认为内联函数(inline):成员函数声明和定义分离就不是内联函数了,不过也不影响,inline只是对编译器的建议,会不会建立栈帧取决于编译器

1.2. 访问限定符

  1. ++用类将对象的属性与方法结合在一起,相当于封装起来了,让对象更加完善,通过访问权限,选择性的提供接口给外部使用。
  2. public(公有)修饰的成员在类外可以使用;protected(保护) private(私有)修饰的成员在类的外面不能被直接访问,目前阶段只需要用public和private就行了,后面涉及到 (继承)。
  3. 访问权限作用域,从当前访问限定符到下一个访问限定符,如果没有访问限定符,作用域就到 } 为止
  4. class 定义的成员没有访问限定符修饰,则默认是privatestruct 默认是public;可以从图中看出,class是默认为private的

1.3. 类域

  1. 类的定义会产生新的域,类的所有成员都在类的作用域中,在类体外定义成员需要使用 : : 指定类域符号声明和定义分离需要指定类域
  2. 类里面时声明,类外面是定义,声明不开辟空间定义会开辟空间

  3. 除了类域还有,全局域和局部域、命名空间域;类域不会影响生命周期,会隔离名字的查找,更改编译器的查找规则
  4. 编译器查找对应函数和定义时默认先查找局部然后是全局,没找到就会报错,如果要查找类域就需要指定

2. 实例化

2.1. 实例化概念

  1. 使用类的类型在物理内存中创建对象的过程,成为类实例化出对象
  2. 类就当相当于是设计图纸,可以做出模具、房子、机器等等;假如说有了房屋设计图纸,设计图纸有房间的厕所的客厅的,利用这个图纸可以建出很多房子
  3. 类就像设计图纸一样,类只是声明没有开辟空间,而房子设计图也一样不能住人,只有实例化出对象才会分配物理内存存储数据,房子也就可以住人了
  4. 类和对象是一对多的关系

#include <iostream>
using namespace std;
class Data
{
public:void time(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()
{Data d1;Data d2;d1.time(2024, 7, 1);d1.Print();d2.time(2024, 4, 1);d2.Print();return 0;
}

2.2. 对象大小

  1. 类可以实例化出对象,那么对象的大小是多少呢?首先可以知道对象中肯定包含成员变量的,那么是否包含成员函数呢?函数被编译后是一条指令,对象无法存储,所以成员函数是存储在代码块的
  2. 如果硬要存储呢?也不是不可以那就只能存储函数的指针了,但是函数调用1000次呢?那我是不是要存1000个函数指针,这样岂不是很浪费空间
  3. 函数指针是不用存储的,函数指针是一个地址,在调用函数的时候会被编译成汇编指令(call地址),编译器在编译时链接的,就要找到函数地址,不是在运行时找,只有多态运行时找

2.2.1. 内存对齐规则

内存的对齐规则其实和结构体一样

  1. 第一个成员放在结构体偏移量为0的地方
  2. 剩下的成员变量要和默认对齐数比较大小,较小值放到地址的对应位置
    1. 注:VS的默认对齐数是 8
  3. 结构体的总大小:最大对齐数的整数倍,计算完后的大小,如果小于最大对齐数的整数倍,就要以整数倍为准
  4. 如果嵌套了结构体,就要对齐到自己结构体的最大对齐数的位置上;
class A
{
public:void Print(){cout << cha << endl;}
private:char cha;int i;short sl;
};
class B
{
public:void Print(){;}
};
class c
{
};
  • B 和 C类对象发现只有一个成员函数,难道大小是 0 吗?其实不是;大小是1;因为一个字节都不给怎么表示对象存在呢?所以这个只是为了标识对象存在
  • 到后面,这种只有成员函数的类有很多

  1. 为什么要内存对齐?不对齐不是更加节省空间吗?
  2. 因为CPU不是能随意读取数据的,每个机器都有默认读取的大小不一样,根地址总线有关系,假设是32根地址总线,那么就是以四个字节来访问
  3. 内存对齐是为减少CPU的访问次数,提高效率
  4. 而左边,第一次读4字节,但只要一个

3.this指针

  1. 下列类中有两个成员函数,函数体中有着不同的对象,那么是怎么区分的呢?,那么它是怎么访问d1 和 d2的;其实C++做了对应处理,隐含的传递了一个this指针解决问题
  2. 编译器编译后,类的成员函数默认都会在形参的第一个,添加一个当前类型的指针,就是说的这个this指针了,当前写的time函数真正的原型是void time(Data* const this,int year, int month, int day)
  3. 类成员内的函数访问变量,可以是this->_year 并赋值;
  4. C++规定在形参和实参部分不可以显示写出this指针,因为这些编译器都会做,但是函数体内可以用this指针访问;其实到现在就可以解释前面的一些小疑惑,它是怎么访问参数的?
#include <iostream>
using namespace std;
class Data
{
public://void time(Data* const this,int year, int month, int day)void time(int year, int month, int day){//在成员函数内可以使用this指针来访问this->_year = year;this->_month = month;this->_day = day;//可以省略写成 _day = day;}//void Print(Data* const this)void Print(){cout << this->_year << '-' << this->_month << '-' << this->_day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Data d1;Data d2;//di.time(&d1,2024, 7, 1); 这里会隐式传递一个this指针d1.time(2024, 7, 1);//d1.Print(&d1);d1.Print();//d2.time(&d2,2024, 4, 1);d2.time(2024, 4, 1);//d2.Print(&d2);d2.Print();
}

小提问:this指针存在内存哪个区域的()

存在内存中的栈,从底层来看是进行了压栈的操作

继续加油!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com