资料来源:南科大 余仕琪 C/C++ Program Design
LINK:
- CPP/week09 at main · ShiqiYu/CPP · GitHub
- 9.1-classes-and-objects_哔哩哔哩_bilibili
- 9.2-constructors-and-destructors_哔哩哔哩_bilibili
- 9.3-this-pointer_哔哩哔哩_bilibili
- 9.4-const-and-static-members_哔哩哔哩_bilibili
0 概述
本节主要介绍类的基本内容,主要包括类定义、构造函数和析构函数、类的使用、以及this指针。
1 Classes and Objects 类和对象
- 操作结构体的数据十分危险,存在数据越界、写入不合规范的数据却无法察觉等问题。
- 使用类进行操作可以很好的解决以上问题。类主要包括成员变量和成员函数。通过成员函数的编写可以更好的规避操作数据中的错误
- 在前面的例子中,我们的成员变量是public类型的。这使得我们并不需要调用成员函数就可以直接外部改变变量的值。一般来说,在类里面我们使用的是private类型的成员变量,pubilc类型的成员函数。这使得我们只能通过调用成员函数来修改。
- 如果不写private,默认为private。
- 如果是private却不用成员函数,直接外部调用,编译环节会直接报错
- 成员函数可以放在类的里面或者类的外面。放在里面的函数默认为inline函数。
- 简单的函数可以放在类里面,复杂的函数(比如打印输出等)则放在外面,这样可以使函数变得更为简洁。
- 成员函数如果放在外面需要加上类的名字,否则就是普通函数。
- 在C++中一般选择将函数和main分开来放,这样显得程序整体的结构更为清晰。
2 构造函数和析构函数
2.1 构造函数
- C++ 中的构造函数是类的一种特殊成员函数,它在每次创建类的新对象时自动执行。构造函数的名称与类的名称相同,不返回任何类型,也不返回
void
。它的主要作用是初始化对象的数据成员。 - 相对于C语言的结构体而言,C++的类在分配内存后需要调用构造函数。如果没有调用构造函数,编译器会自动生成一个空的构造函数,如下所示。
class Line {
public:
Line(); // 这是构造函数
private:
double length;
};
Line::Line() {
cout << "Object is being created" << endl;
}
- 一个类里可以有多个构造函数,只需要参数不同即可。这些构造函数也称为重载构造函数。
- 变量初始化也可以写成以下简洁形式
2.2 析构函数
- 析构函数(destructor)在 C++ 中是一种特殊的成员函数,与构造函数相反。当对象结束其生命周期,例如对象所在的函数已调用完毕时,系统会自动执行析构函数。它的主要作用是进行一些“清理善后”的工作,例如释放对象创建时申请的内存空间。
- 析构函数只能有一个,不可以重载。
- 与构造函数类似,析构函数无返回值,没有参数列表,且只能有一个析构函数。
delete
:这个运算符用于释放单个对象指针指向的内存。delete []
:这个运算符用于释放对象数组指针指向的内存。它会为数组中的每个元素调用析构函数,然后释放内存。
3 this 指针
- 在 C++ 中,this 指针是一个特殊的指针,它指向当前对象的实例。每一个对象都能通过 this 指针来访问自己的地址。这个隐藏的指针可以在类的成员函数中使用,用来指向调用该函数的对象。当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为 this 指针
- 有了this指针,就可以特指当前对象的成员变量或成员函数去调用
4 const 和 static 成员
4.1 const
- 回顾const声明
- c++中不推荐用第一种 #define 类型的宏定义来定义常量,都使用const来定义。
-
const int * p_int;
:这表示p_int
是一个指向常量整数的指针。具体来说:
p_int
可以指向不同的整数变量,但是不能通过*p_int
修改所指向的整数的值。- 例如,
*p_int = 42;
是非法的,因为p_int
所指向的整数是常量。
-
int const * p_int;
:这与上面的声明相同,也表示p_int
是一个指向常量整数的指针。const
关键字在int
前后都可以放置,效果相同。 -
int * const p_int;
:这表示p_int
是一个指向整数的常指针。具体来说:
p_int
的值(即所指向的内存地址)不能改变,一旦初始化,就不能再指向其他地方。- 但是,可以通过
*p_int
修改所指向的整数的值。
- 成员里面也可以定义常量。可以是成员变量或者是成员函数。作为成员函数时,不能对变量进行修改。
4.2 static
静态成员(static members)包括静态成员变量和静态成员函数。它们有一些独特的特性和用途:
静态成员变量
-
定义和声明:
- 静态成员变量在类中声明,但必须在类外定义。
- 使用关键字
static
进行声明。
class MyClass { public: static int staticVar; }; // 在类外定义 int MyClass::staticVar = 0;
-
共享性:
- 静态成员变量在所有对象之间共享,所有对象访问的是同一个变量。
- 修改一个对象的静态成员变量会影响所有对象。
-
生命周期:
- 静态成员变量在程序开始时分配内存,并在程序结束时释放。
静态成员函数
-
定义和声明:
- 静态成员函数使用关键字
static
进行声明。 - 它们不能访问类的非静态成员变量或非静态成员函数。
class MyClass { public: static void staticFunction(); }; void MyClass::staticFunction() { // 只能访问静态成员变量 staticVar = 10; }
- 静态成员函数使用关键字
-
调用方式:
- 静态成员函数可以通过类名直接调用,不需要创建对象。
- 也可以通过对象调用,但不推荐。
MyClass::staticFunction(); // 推荐 MyClass obj; obj.staticFunction(); // 也可以,但不推荐
用途
- 静态成员变量:常用于需要在所有对象之间共享数据的场景,例如计数器、配置参数等。
- 静态成员函数:常用于不依赖于对象实例的操作,例如工厂方法、实用工具函数等。
静态成员变量和普通成员变量在C++中有几个关键区别:
-
归属:
- 静态成员变量:属于类本身,而不是类的某个对象。所有对象共享同一个静态成员变量。
- 普通成员变量:属于类的某个对象,每个对象都有自己独立的普通成员变量。
-
定义和声明:
- 静态成员变量:在类中声明,但必须在类外定义。
class MyClass { public: static int staticVar; }; int MyClass::staticVar = 0; // 在类外定义
- 普通成员变量:在类中声明和定义。
class MyClass { public: int nonStaticVar; };
- 静态成员变量:在类中声明,但必须在类外定义。
-
访问方式:
- 静态成员变量:可以通过类名直接访问,也可以通过对象访问。
MyClass::staticVar = 10; // 通过类名访问 MyClass obj; obj.staticVar = 20; // 通过对象访问
- 普通成员变量:只能通过对象访问。
MyClass obj; obj.nonStaticVar = 30;
- 静态成员变量:可以通过类名直接访问,也可以通过对象访问。
-
生命周期:
- 静态成员变量:在程序开始时分配内存,并在程序结束时释放。
- 普通成员变量:在对象创建时分配内存,并在对象销毁时释放。
-
共享性:
- 静态成员变量:在所有对象之间共享,修改一个对象的静态成员变量会影响所有对象。
- 普通成员变量:每个对象都有自己独立的副本,修改一个对象的普通成员变量不会影响其他对象。