目录
一、类的定义
1.1类的定义格式
1.2访问限定符
1.3类域
二、实例化
2.1实体化的概念
2.2类对象的大小
三、this指针
前言:
这篇文章是对类和对象的初步介绍,我将用三篇文章描述类和对象,希望对大家有所帮助
一、类的定义
什么是对象:
对象是一个实体,我们眼睛能看到的实体都是对象。
什么是类:
类是用来对实体(对象)进行描述的,如对象有什么属性,功能等。类可以看做C语言中的结构体的加强版,在C++中结构体被认为是类的一种。
1.1类的定义格式
class是类的关键字,stack是类的名字,{}中是类的成员,注意类定义结束时后⾯分号不能省略,类中的成员包括变量和函数。类中的变量称为类的属性或成员变量,类中的函数称为类的⽅法或 者成员函数。
#include<iostream>
using namespace std;
class stack//类型名
{//类的成员// //函数称为类的⽅法或 者成员函数void add()此时为内联函数{//.......}//类的属性或成员变量int a = 10;int b = 0;
};//后⾯分号不能省略
//第二种,可以把声明留在类里,定义放在外面或别的文件
///比如类的声明在.h文件,定义在.c文件
//.h文件
class stack//类型名
{//类的成员// //函数称为类的⽅法或 者成员函数
public:void add();//类的属性或成员变量int a = 10;int b = 0;
};//后⾯分号不能省略
//.c文件
void stack::add()
{//........
}
类的定义中需要注意的细节:
①.C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是 struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类。
②在类中定义的成员函数,默认为是内联函数(inline)
③为了避免函数形参和类中的成员函数名相同,为了避免混淆最好加上一些特殊标记。
④两种定义方法都可以使用,必进编译器会忽略长函数,我们可以将短的函数写在里面,长的函数写在外面
1.2访问限定符
访问限定符是C++的一种封装方式,将类的属性和类的方法联系在一起,通过访问限制选择性的将一些内容给外界使用。
public | 修饰的成员在类外可以直接被访问 |
private | 修饰的成员在类外不能直接被访问 |
protected | 修饰的成员在类外不能直接被访问 |
访问限定符中的细节:
①一个访问限定符的作用域,从这个访问限定符开始到下一个访问限定符结束,如果没有就到}结束。
②class当类内没有访问限定符时,默认为private;struct中默认为public。
③public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,这里我们还未详细讲解,以后继承章节才能体现出他们的区别。
④public在类外和类内都可以被直接访问。
class stack
{
public:int a = 10;int b = 3;
private:void add(){//.....}
protected:int c = a + b;//public在类内可以直接访问add();//private不可以直接访问
};
1.3类域
上一篇文章我们讲了C++中的域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响 编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
类域是一个全新的作用域,在类外要定义时,需要使⽤ :: 作⽤域操作符指明成员属于哪个类域。
class stack
{
public:void STinit(int n=4);
private:int val;int top = 0;int capacity = 4;
};
void stack::STinit(int n = 4)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail!");}
}
int main()
{stack st;st.STinit();
}
二、实例化
2.1实体化的概念
如果说类是对对象的描述,而对象可以是眼睛看到的任何实体,那我们也可以认为对象是一个房子时,类是对房子的描述,即为图纸。在没有实体化的时候,是不占空间的。
类是可以定义多个对象的,就像一个图纸可以建很多个房子。
class stack
{
public:void STinit(int n=4);
private:int val;int top = 0;int capacity = 4;
};
void stack::STinit(int n = 4)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail!");}
}
int main()
{stack st1;stack st2;st1.STinit();st2.STinit();
}
2.2类对象的大小
之前我们在上面讲述了Class是C语言中struct的加强版,那么类对象的大小,是否和结构体的大小有关呢?
答案是相关的,但是也有一些不同。
①类中包含成员变量和成员函数,类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含 成员变量,那么成员函数是否包含呢?
→→⾸先函数被编译后是⼀段指令,对象中没办法存储,这些指令存储在⼀个单独的区域(代码段),那么对象中⾮要存储的话,只能是成员函数的指针
→→对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各⾃独⽴的成员变量 _year/_month/_day存储各⾃的数据,但是d1和d2的成员函数Init/Print指针却是⼀样的,存储在对象 中就浪费了。如果⽤Date实例化100个对象,那么成员函数指针就重复存储100次,太浪费了。
→→所以成员函数不在类中存储,他们在公共的代码区中存储。
这样类中就只用存储成员变量这与结构体就相同了,遵循内存对齐规则。
如果这个类是空(没有成员变量)的,没有成员,那就是1个字节,不存数据,就标识有这个对象存在过。
三、this指针
Date类中有print和init成员函数,由上可知他们存储在相同位置,当我们创建不同Data的不同对象时,如何分辨是谁的函数呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题。
编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。⽐如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day)
类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this- >_year = year;
C++规定不能在实参和形参的位置显⽰的写this指针(编译时编译器会处理),但是可以在函数体内显 ⽰使⽤this指针。
#include<iostream>
using namespace std;
class Date
{
public:// void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){// 编译报错:error C2106: “=”: 左操作数必须为左值// this = nullptr;// this->_year = year;this->_year = year;this->_month = month;this->_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:// 这⾥只是声明,没有开空间int _year;int _month;int _day;
};
int main()
{// Date类实例化出对象d1和d2Date d1;Date d2;// d1.Init(&d1, 2024, 3, 31);d1.Init(2024, 3, 31);d1.Print();d2.Init(2024, 7, 5);d2.Print();return 0;
}