一、类的定义
class,struct 为类定义的关键字
类中的变量称为类的属性或成员变量
函数称为类的方法或成员函数
为了区分成员变量,一般习惯上成员变量会加一个特殊标识,
如前缀 _ 或 m_ ,并不是强制的,只是一些惯例,具体看公司的要求。
C++ 中 struct 也可以定义类,C++ 兼容 C 中 struct 的用法,
同时 struct 升级成了类,明显的变化是 struct 中可以定义函数。
一般情况下推荐用 class 定义类。
一个类的函数可以在类内声明、类外定义,
但前面一定要加 类名:: ,否则编译报错。
二、访问限定符
C++ 一种实现封装的方式:用类将对象的属性与方法结合在一起,通过访问权限选择性地将其接口提供给外部的用户使用。
-
public:修饰的成员在类外可以直接被访问;
-
protected 和 private:修饰的成员在类外不能直接被访问(这两者的区别后续再讲解)。
访问权限的作用域:从该访问限定符出现的位置开始,直到下一个访问限定符出现时为止;
如果后面没有其他访问限定符,作用域到类结束。
-
class 的成员默认是 private
-
struct 的成员默认是 public
⚠️ 注意:访问限定符后面需要加冒号。
// 知识点:class 的成员默认是 private
class Student {
// 【默认权限区域】
// 这里没有写限定符,所以默认是 private。
// 类外无法直接访问,只能在类内部的成员函数中操作。
string name;
int age;
public:
// 【public 权限区域】
// 从 public: 开始,到下一个限定符(或类结束)为止,都是公开的。
// 类外可以直接调用这些函数(这就是你提到的"接口")。
// 构造函数(也是 public 的)
Student(string n, int a) {
// 在成员函数内部,可以随意访问 private 的 name 和 age
name = n;
age = a;
}
// 提供一个公开的接口,让外部获取名字
void showInfo() {
cout << "姓名:" << name << ",年龄:" << age << endl;
}
private:
// 【private 权限区域】
// 作用域从这里开始,直到类结束。
// 这里适合放一些不想让外部知道的内部数据或辅助函数。
int studentID;
void internalCheck() {
// 这是一个内部的私有函数,外部无法调用
cout << "正在进行内部检查..." << endl;
}
};
// 知识点:struct 的成员默认是 public
struct DataNode {
int val; // 默认是 public,外部可以直接 data.val 访问
DataNode* next; // 默认是 public
};
三、类与对象的内存特点
-
类实例化出的每个对象,都有独立的数据空间;
-
对象中包含成员变量,成员函数是多个对象共用的;
-
类即使只有成员函数,也会占用至少1字节的内存(用于占位标识)。
四、this 指针 指向对象的指针
指向的是"当前正在调用这个函数的那个对象"
一个类的两个对象,使用同一个成员函数
函数如何分辨哪个对象调用的函数?
用 this 指针 悄悄把对象指针传过去
this 是一个形参,把对象地址传过去
在 形参、实参都不能显式的去写 this
函数内可以显式的加上 this,结果为类指针
实际代码中什么时候需要显式写 this?
1、解决形参和成员变量"撞名"的尴尬
这是最常见的用法。为了代码可读性,我们常把构造函数的形参名设得和成员一样,这时候必须用 this 来区分:
class Student {
public:
int age;
Student(int age) {
// 这里的 age 是形参,this->age 才是成员变量
this->age = age;
}
};
2、实现"链式调用"(返回当前对象本身)
如果你想让函数调用像流水线一样连起来(比如 obj.setA(1).setB(2)),就需要返回 *this:
class Calculator {
public:
int val = 0;
// 返回类指针(或者类引用 *this)
Calculator* add(int x) {
val += x;
return this; // 把当前对象的地址抛回去,方便下一次调用
}
};
// 使用:calc.add(5).add(10);
3、把当前对象作为参数传给别的函数
比如当前对象想把自己"介绍"给另一个对象或全局函数:
void globalFunc(Student* s);
class Student {
public:
void introduce() {
globalFunc(this); // 显式把当前对象的指针传出去
}
};
this 默认认为存在栈 vs 优化存在寄存器