1. 类与对象简介
1.1 什么是类和对象
- 类(Class)是C++中创建用户自定义类型的一种方式,它将数据(成员变量)和操作数据的函数(成员函数)封装在一起。
 - 对象(Object)是类的实例化,拥有类定义的所有属性和行为。
 - 类更像是汽车图纸,对象更像是造出来的汽车。
 
1.2 类的作用
- 封装(Encapsulation):将数据和操作数据的代码绑定在一起,保护数据不被外界直接访问。
 - 抽象(Abstraction):通过类定义抽象出具有共同特性的对象,提高代码的可重用性和可维护性。
 - 继承(Inheritance)和多态(Polymorphism):实现代码的复用与动态绑定。
 
2. 类的定义
2.1 基本语法
1  | class ClassName {  | 
2.2 示例
创建一个表示学生的类:
1  | 
  | 
3. 成员变量与成员函数
3.1 成员变量
- 成员变量(Member Variables):用于存储对象的状态信息。
 - 命名约定:常用下划线结尾(例如 
name_)表示成员变量,避免与局部变量混淆。 
3.2 成员函数
- 成员函数(Member Functions):定义对象的行为,可以访问和修改成员变量。
 - 常成员函数(Const Member Functions):保证函数不会修改对象的状态。
 
3.3 示例实现
1  | // Student.cpp  | 
4. 访问控制
4.1 访问修饰符
- public:公有成员,可以被所有代码访问。
 - private:私有成员,仅能被类的成员函数和友元访问。
 - protected:受保护成员,仅能被类的成员函数、友元和派生类访问。
 
4.2 例子
1  | class Sample {  | 
5. 构造函数与析构函数
5.1 构造函数
- 默认构造函数:没有参数的构造函数。
 - 参数化构造函数:接受参数以初始化对象。
 - 拷贝构造函数:用一个对象初始化另一个对象。
 - 移动构造函数(C++11):从临时对象“移动”资源。
 
5.2 析构函数
- 析构函数(Destructor):在对象生命周期结束时调用,用于释放资源。
 
5.3 示例
1  | 
  | 
5.4 使用示例
1  | int main() {  | 
输出示例:
1  | Default constructor called.  | 
5.5 拷贝构造是否必须实现
当一个类A中有成员变量是另一个类类型B的时候,有时候拷贝构造会失效。比如一个类A中有成员变量std::thread,std::thread没有构造函数,所以A类的拷贝构造无法合成,需要显示编写。
同样析构也要显示编写,等待线程完成。
除此之外我们可以自己实现拷贝构造,进而实现浅拷贝和深拷贝的不同效果


5.6 构造顺序和析构顺序
类A中包含成员变量是类B的类型,如果是先调用A的构造还是B的构造呢?
如果析构的时候是A先析构还是B先析构呢?
5.7 类默认构造是否必须实现
如果类中有继承关系或者其他类型的成员,默认构造函数是很有必要实现的。
系统提供的合成的默认构造函数不会对成员做初始化操作。
5.8 this 指针的特性和用途
指向当前对象:
this指针是一个隐式参数,指向调用成员函数的对象。通过this,你可以访问当前对象的属性和方法。
区分成员变量和参数:
在构造函数或成员函数中,参数名和成员变量可能同名。使用
1
this
可以明确指代成员变量。例如:
1
2
3
4
5
6
7
8class MyClass {
private:
int value;
public:
MyClass(int value) {
this->value = value; // 使用 this 指针区分成员变量和参数
}
};
返回当前对象:
- ```
this1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
可以用于返回当前对象的引用,以支持链式调用。例如:
```cpp
class MyClass {
private:
int value;
public:
MyClass& setValue(int value) {
this->value = value;
return *this; // 返回当前对象的引用
}
};
MyClass obj;
obj.setValue(10).setValue(20); // 链式调用 
- ```
 在 const 成员函数中的使用:
- 在 
const成员函数中,this的类型为const MyClass*,这意味着你不能通过this修改成员变量。这有助于确保对象的状态不被改变。 
- 在 
 在静态成员函数中的不可用性:
- 静态成员函数没有 
this指针,因为它们不属于任何特定对象,而是属于类本身。因此,静态成员函数不能访问非静态成员变量和成员函数。 
- 静态成员函数没有 
 
示例代码
以下是一个简单的示例,展示了 this 指针的用法:
1  | 
  | 
5.9 delete和default
C++11用法:
delete可以删除指定的构造函数。
default可以指定某个构造函数为系统默认合成。
6. 拷贝控制
拷贝构造函数与拷贝赋值运算符
6.1 拷贝构造函数
- 定义:用于创建一个新对象,并复制现有对象的成员。
 - 语法:
ClassName(const ClassName& other); 
6.2 拷贝赋值运算符
- 定义:用于将一个已有对象的值赋给另一个已有对象。
 - 语法:
ClassName& operator=(const ClassName& other); 
6.3 示例
1  | 
  | 
6.4 使用示例
1  | int main() {  | 
输出示例:
1  | Constructor called.  | 
7. 移动语义
7.1 什么是移动语义
- 移动语义(Move Semantics):允许资源的所有权从一个对象转移到另一个对象,避免不必要的拷贝,提高性能。
 
7.2 移动构造函数与移动赋值运算符
- 移动构造函数:
ClassName(ClassName&& other) noexcept; - 移动赋值运算符:
ClassName& operator=(ClassName&& other) noexcept; 
7.3 示例
1  | 
  | 
7.4 使用示例
1  | int main() {  | 
输出示例:
1  | Constructor called.  | 
8. 类的友元
8.1 什么是友元
- 友元(Friend):可以访问类的私有和保护成员的非成员函数或另一个类。
 
8.2 类型
- 友元函数:单个函数可以被声明为友元。
 - 友元类:整个类可以被声明为友元。
 
8.3 使用示例
1  | 
  | 
8.4 使用友元类
1  | class Rectangle {  | 
9. 运算符重载
9.1 什么是运算符重载
- 运算符重载(Operator Overloading):允许对自定义类型使用C++运算符,如 
+,-,<<等。 
9.2 重载运算符的规则
- 只能对已有运算符进行重载,不能创建新运算符。
 - 至少有一个操作数必须是用户定义的类型。
 - 不能改变运算符的优先级或结合性。
 
9.3 示例:重载 + 运算符
1  | 
  | 
9.4 示例:重载 << 运算符(输出流)
1  | 
  | 
输出示例:
1  | Employee Name: John Doe, Salary: $75000  | 
10. 练习示例
项目:实现自定义MyString类
目标:创建一个简单的MyString类,支持拷贝构造,默认构造,有参构造,支持输出和比较等。
1  | 
  | 
代码说明
- 私有成员:
char* data:指向动态分配的字符数组,用于存储字符串。
 - 构造函数:
- 默认构造函数:初始化 
data为nullptr。 - 有参构造函数:接收一个 
const char*类型的字符串,动态分配内存并复制字符串内容。 - 拷贝构造函数:复制另一个 
MyString对象的内容,确保深拷贝。 
 - 默认构造函数:初始化 
 - 赋值运算符重载:支持将一个 
MyString对象赋值给另一个,确保释放原有内存并进行深拷贝。 - 比较运算符重载:支持比较两个 
MyString对象是否相等。 - 输出运算符重载:支持直接使用 
std::cout输出MyString对象。 - 析构函数:释放动态分配的内存,防止内存泄漏。
 
使用示例
在 main 函数中,创建了几个 MyString 对象,演示了拷贝构造、赋值和比较的用法。
视频教程
关于C++的视频教程可参考我的主页