【c++】类和对象(上)this指针、空指针解引用易错点
引入:在C语言里,我们的结构体里面是不能够定义函数的,而C++里的类里面却可以定义函数,我们可以将类看作是C语言结构体的plus版。定义类的关键字为class。类是类似于结构体的一种用户自定义的数据类型。struct 的升级:struct 升级成了类,主要体现在C++里的 struct 里面可以定义函数了代码语言:javascriptAI代码解释class Date//类的名字//类的主体:由成员
一、面向过程和面向对象的初步认识
1.C语言面向的是过程,面向过程以函数为中心,程序由一系列函数调用组成。它关注解决问题的步骤(怎么做)。 2.C++面向的是对象,面向对象以对象为中心,程序由多个对象的交互组成。它关注的是对象之间的关系(谁来做)。
就比如交作业: C语言: 我把作业交给课代表->课代表拿到作业并检查->课代表把作业交给老师 C++: 我->课代表->老师
- 对于面向过程,我们需要操纵每个对象去实现对应的工作(函数调用)
- 对于面向对象,每个对象知道自己要做些什么,不需要我们进一步的操纵
二、类的定义
引入:在C语言里,我们的结构体里面是不能够定义函数的,而C++里的类里面却可以定义函数,我们可以将类看作是C语言结构体的plus版。定义类的关键字为 class。类是类似于结构体的一种用户自定义的数据类型。
- struct 的升级:struct 升级成了类,主要体现在C++里的 struct 里面可以定义函数了
2.1 类的定义格式
代码语言:javascript
AI代码解释
class Date//类的名字
//类的主体:由成员函数和成员变量组成
{
public:
//成员函数
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
//成员变量
int _year;
int _month;
int _day;
};
};
1.格式定义:
1.定义类的关键字:class,虽然 struct 也可以定义类,但一般情况下还是推荐由 class 来定义。 2.Date为类的名字。 3.花括号里的是类的主体,简称类体。 4.类体由成员函数和成员变量组成,其中成员函数也叫做类的方法,成员变量也叫做类的属性。成员变量和成员函数都是类的成员。
2.为了区分成员变量,我们一般在定义成员变量的时候,会在变量名称之前或之后加一个特殊符号比如_。比如上面代码成员变量 year、month、day 加_是为了更好区分它们和函数的形参。这个并不强制,只是惯例。 3.定义在类里面的成员函数默认为inline。
2.2 访问限定符
C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限选择性的将其接⼝提供给外部的⽤⼾使⽤。 访问限定符分为:public(共有)、protected(保护)、private(私有)

在这里插入图片描述
- 由 public 修饰的成员在类外可以直接被访问。
- 由 protected 和 private 修饰的成员在类外不可以被直接访问(我们目前阶段可以认为 protectd 和 private 差不多)
- 划分区域:从一个访问限定符开始,直到下一个访问限定符或者是遇到 ‘}’ 为止。
- 由 class 定义的类,其成员默认被 prevate 修饰。
- 由 struct 定义的类,其成员默认被 public 修饰。
2.3 类域
类定义了⼀个新的作⽤域,类的所有成员都在类的作⽤域中,在类体外定义成员时,需要使⽤ :: 作⽤域操作符指明成员属于哪个类域。比如接下来要提到的第二种定义方式。
2.4 两种定义方式
2.3.1 声明与定义不分开
- 声明和定义全部放在类体中。这种情况下,编译器可能会将成员函数当作内联函数来处理
代码语言:javascript
AI代码解释
//.h文件
class Stack
{
public:
// 成员函数
void Init(int n)
{
arr = (int*)malloc(sizeof(int) * n);
if (nullptr == arr)
{
perror("malloc fail");
return;
}
capacity = n;
top = 0;
}
private:
// 成员变量
int* arr;
size_t capacity;
size_t top;
};
2.3.2 声明与定义分开
- 类的声明放在 .h文件里,类的定义放在 .cpp文件里。
- 在类体外定义函数时,别忘了使用 :: 作用域操作符,并指明在哪个域里。
代码语言:javascript
AI代码解释
//.h文件
class Stack
{
public:
// 成员函数
void Init(int n = 4);
private:
// 成员变量
int* arr;
size_t capacity;
size_t top;
};
//.cpp文件
// 声明和定义分离,需要指定类域
void Stack::Init(int n)
{
arr = (int*)malloc(sizeof(int) * n);
if (nullptr == arr)
{
perror("malloc fail");
return;
}
capacity = n;
top = 0;
}
三、类的实例化
概念:
- 什么是对象?类是一种用户自定义的数据类型,可以类比利用结构体类型定义变量。而对象就是类这种数据类型定义的变量即实例。
- 而类的实例化就是类在物理空间下创建出对象的过程,对象就是类的具体实例。
- 类是抽象的,而对象是具体的。可以说,类是对对象的一种抽象化的描述。类只是限定了对象有哪些成员变量,类只是声明,它并没有为这些成员变量分配空间。只有当类实例化为对象时,才会为这些成员变量分配内存。
- 类可以实例化多个对象,这些对象都占有一定的物理空间。类就好比是一个建筑图纸,它是抽象的,不能住人,不能实现房子的功能。而对象就是依照这副图纸造出来的房子,能够实现房子的功能。
四、类对象模型
4.1 基本模型
- 类对象中只储存成员变量,不储存成员函数。
- 成员函数放在公共代码区,只要是这个类实例化出的对象,就都可以使用这个函数。
不储存成员函数的原因: 函数名的本质是指向函数代码内存地址的指针。倘若每个对象都要存储这个成员函数,相当于每个对象都要储存这个函数的指针,而函数的地址是不变的,这是一种对于空间的浪费。
4.2 类对象大小计算方法
- 类对象的大小就是其中成员变量所占内存之和,计算方法与结构体相同,也遵循结构体内存对齐规则。
- 对于没有成员变量的对象,编译器会为其分配 1 字节大小的内存,相当于占位。
测试:
代码语言:javascript
AI代码解释
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 计算⼀下A/B/C实例化的对象是多⼤?
class A
{
public:
void Print()
{
cout << _ch << endl;
}
private:
char _ch;
short _s;
};
class B
{
public:
void Print()
{
//...
}
};
class C
{};
int main()
{
A a;
B b;
C c;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(c) << endl;
return 0;
}
结果:

在这里插入图片描述
五、this指针
我们看下面的一段代码:
代码语言:javascript
AI代码解释
#include<iostream>
using namespace std;
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 d1, d2;
d1.Init(2025, 5, 4);
d2.Init(2025, 5, 5);
d1.Print();
d2.Print();
return 0;
}
测试结果:

在这里插入图片描述
我们能够观察到: Date类中有 Init() 和 Print() 这两个成员函数,我们在对 d1 和 d2 这两个对象进行初始化和打印的时候,函数是怎么知道我们是针对的哪个呢?因为我们并没有将对象的地址传入。
-------这是因为C++里引入了一个隐含的 this 指针来解决这个问题。它不由用户主动添加,而由编译器完成添加。
更多推荐
所有评论(0)