目录
[1. 类的定义](#1. 类的定义)
[1.1 定义格式](#1.1 定义格式)
[1.2 访问限定符](#1.2 访问限定符)
[1.3 类域](#1.3 类域)
[2. 类的实例化](#2. 类的实例化)
[2.1 实例化对象大小](#2.1 实例化对象大小)
[3. 隐含this指针](#3. 隐含this指针)
1. 类的定义
C++的结构体在C语言结构体的基础上增加了函数和访问控制等操作,而C++的类和C++的结构体除了默认访问权限 外完全相同。
(另外在struct方面,C++还实现了声明时可以省略写struct,直接写结构体名的步骤:
cpp
struct Student {
char name[20];
int age;
};
// 定义变量时不需要struct
Student s1;
Student* p;
说回正题:
- 类是一个自定义的数据类型,通常用于将功能相近的数据和操作绑定在一起,本质是结构体和函数指针的语法糖。
- 对象是类的具体实现,也称作类的实例化,是在内存中真实开辟出空间来存储的。
举个例子,类是建筑的蓝图,而对象则是根据这个蓝图创建出的一个个房屋,是具体存在的。

1.1 定义格式
类由以下部分组成:
- 关键字class
- 类名Stack(自定义名称,类名即类型)
- 类的主体(存放在{}中,包括成员变量和成员函数)
- 分号 (易漏)
C++中struct 也可以定义类,但struct的默认访问权限是public,class是private ,为了保护数据安全,大部分情况下,类都使用class实现。
cpp
class Stack // 关键字和类名
{
private:
// 成员变量
int* arr;
int _size;
int _capacity;
public:
// 成员函数
void Print();
void Destroy();
void Push(int x);
};
// 分号
补充知识:
- C++中类的成员变量名通常会加上特殊标识 方便区分,例如下划线_或者m(表示member)
- 声明和定义都在类内的函数默认为inline函数
- 类内部成员的声明顺序没有强制要求
1.2 访问限定符
访问限定符包括:public,private,protected
| 访问级别 | 自己(本类) | 子类(派生类) | 外部 |
|---|---|---|---|
public |
能访问 | 能访问 | 能访问 |
protected |
能访问 | 能访问 | 不能访问 |
private |
能访问 | 不能访问 | 不能访 |
protected和private的区别会在继承显著体现。
用法和注意事项:
访问限定符的作用域:始于该限定符 ,止于下一个访问限定符。
class默认权限为private ,struct默认权限为public。
一般来说,我们将成员变量设为private ,成员函数设为public,这样既能保护变量安全,又能通过函数接口来操作对象。
1.3 类域
类构成了一个独立 的作用域,必须通过**作用域解析运算符 ::**才能访问其成员。
设置类域是为了方便编译器查找 ,指定了类域后编译器在编译时就会自动去对应的类中查找 ;如果未指定又试图访问类内部成员,那么编译器只会在全局查找 对应成员的声明和定义,最终导致无法找到而报错。
另外,一般来说类中成员函数的声明和定义是分离的 (除了有意设置为inline函数),而在类外定义就需要使用作用域操作符::。
**Q:**声明和定义有什么区别?
A: 声明无需分配内存空间,而定义则需分配内存空间。
举个例子:
cpp
#include<iostream>
using namespace std;
class Stack
{
public:
void Init(int n = 4);
private:
// 只是声明,未开空间
int* array;
size_t capacity;
size_t top;
};
// 声明和定义分离,需要指定类域
void Stack ::Init(int n)
{
array = (int*)malloc(sizeof(int) * n);
if (nullptr == array)
{
perror("malloc申请空间失败");
return;
}
capacity = n;
top = 0;
}
C++类成员的三种访问方式:
cpp
class Student {
public:
static string school;
string name;
void print();
};
// 静态成员变量类外初始化
string Student::school = "默认学校";
// 类外定义成员函数
void Student::print() {
cout << name << endl;
}
int main() {
// 1. 通过对象
Student s;
s.name = "Tom";
s.print();
// 2. 通过指针
Student* p = &s;
p->name = "Jerry";
p->print(); // 编译器会转化为print(p)
// 3. 通过类名(静态成员)
Student::school = "xx学校";
return 0;
}
2. 类的实例化
一个类可以实例化出多个对象,这些对象开辟了空间,是可以直接在内存中找到的。
2.1 实例化对象大小
对象在内存中的存储方式和struct类似,都是通过内存对齐的方式存储的。
**Q:**为什么存在内存对齐规则?
A: CPU读取数据时并非从任意位置开始读取任意大小,而是按照固定对齐方式从整数倍地址处读取固定长度的数据块。若数据未按内存对齐规则存储,可能导致CPU需要分多次读取并拼接数据,从而降低访问效率。内存对齐机制的核心作用就是优化CPU的数据读取性能。
但是对象仅仅会为成员变量多次开辟空间,对于成员函数而言,每个对象的成员函数功能都是一样的,没必要单独开辟多个空间存储函数指针,因此计算对象大小时仅需关注成员变量即可。
内存对齐规则和C的结构体规则类似,详细介绍可以看博主的这篇博客:
嵌套类和嵌套结构体的计算方式相同。
Q: 如果一个对象中什么成员变量也没有存放,那么大小为多少呢?
cpp
class A
{
public:
void Print();
};
int main()
{
A a;
cout << sizeof(a) << endl;
return 0;
}
A: 实例化对象就需要分配内存空间,因此设置为1个字节,仅仅作为占位符使用,不存储实际数据。运行后如下图:

3. 隐含this指针
Q:类内声明 的成员函数,放在类外定义 时并没有通过限定符::访问,那么成员函数如何区分不同对象呢?
A: 因为在编译器编译后,类的成员函数会默认在第一个形参的位置增加一个指向当前对象地址的this指针,类中的成员函数,本质都是通过this指针访问成员变量的。
如下:
cpp
// 代码显式写的
void A::Print()
{
cout << _size << end;
cout << _capacity << endl;
}
// 编译器底层转换
void A::Print(A* const this)
{
cout << this->_size << endl;
cout << this->_capacity << endl;
}
注意事项:
C++规定不能 在实参和形参 位置显式写this指针(编译器在编译时会自动处理),也不能传入对象的地址;但是可以在函数内部显式使用this指针。
如下:
cpp
// 形参部分不能写
void A::Print()
{
// 可以在内部显式使用
cout << this->_size << endl;
cout << this->_capacity << endl;
}
this指针本质上是函数的形参,因此this指针是存储在栈中的。
// 感谢阅读,欢迎讨论交流= ̄ω ̄= 封面是soyo酱🤗