C++入门05 类与对象

图源:文心一言

听课笔记简单整理,供小伙伴们参考~🥝🥝

  • 第1版:听课的记录代码~🧩🧩

编辑:梅头脑🌸

审核:文心一言


目录

🐳类与对象

🐳函数

🐋4.2 默认构造函数

🐋4.5 类的组合程序

🐋4.6 前向引用

🐋4.7 结构体

🐋4.8 联合体

🐋4.9 枚举类

🐋4.10 组合类例题

🔚结语


🐳类与对象

  • 郑莉老师的公开课:🌸C++语言程序设计基础 - 清华大学 - 学堂在线 (xuetangx.com)

🐳函数

🐋4.2 默认构造函数

🧩题目

构造钟表类。

📇算法思路

——

⌨️算法代码

#include <iostream>
using namespace std;

class Clock {      // Clock类的定义
public:            // 公有成员,外部接口  
    Clock(int newH, int newM, int newS);  // 构造函数:接受3个参数newH、newM、newS,并分别赋给hour、minute、second   
    Clock();                              // 默认构造函数:如果没有特别指定hour、minute和second的值,那么它们将默认被设置为0  
    void setTime(int newH = 0, int newM = 0, int newS = 0); // 设置时间:接受3个可选参数newH、newM、newS,并分别赋给hour、minute、second。如果没有提供参数,则使用默认值0。  
    void showTime();                                        // 显示时间:打印当前时钟的时间到控制台  
private:           // 私有成员,类内可见
    int hour, minute, second;
};

// 构造函数 
Clock::Clock(int newH, int newM, int newS) :
    hour(newH), minute(newM), second(newS) {
}

// 默认构造函数 
Clock::Clock():hour(0),minute(0),second(0){
}

// showTime函数
void Clock::setTime(int newH, int newM, int newS) {
    hour = newH;
    minute = newM;
    second = newS;
}
// showTime函数
void Clock::showTime() {
    cout << hour << ":" << minute << ":" << second << endl;
}

int main()
{
    Clock c1(8, 10, 0); // 调用构造函数,创建一个Clock对象c1,并设置时间为8:10:00  
    Clock c2;           // 调用默认构造函数,创建一个Clock对象c2,使用默认时间0:0:0  
    c1.showTime();      // 显示 c1 的时间
    c2.showTime();      // 显示 c2 的时间
    c2.setTime(1, 1, 1);    // 使用settime,重新设置c2的时间为1:1:1  
    c2.showTime();          // 显示 c2 的时间
    return 0;
}

📇执行结果

📇相关概念

类(Class)

在面向对象编程中,类可以被看作是创建对象的模板或蓝图。它定义了对象应该具有的属性和可以执行的方法。

以上述代码为例,Clock 就是一个类,它代表了时钟的概念。这个类定义了时钟应该具有的属性,如小时、分钟和秒。同时,它也定义了时钟可以进行的行为,比如设置时间和显示时间。

当我们根据Clock类创建对象时,这些对象就会具有类所定义的属性和方法。在上述代码中,c1 和 c2 就是根据Clock类创建的具体对象。我们可以为这些对象设置具体的时间值,比如将c1的时间设置为8小时10分0秒,或者不设置其值,让它默认为0小时0分0秒。通过这些对象,我们可以方便地操作和管理与时钟相关的数据和行为。

类的成员(Class Members)

类的成员包括数据成员(通常称为属性或字段)和函数成员(通常称为方法)。

  • 数据成员(Data Members):
    • 数据成员是类中存储数据的变量。在上述代码中,Clock 类有三个私有数据成员:hourminute 和 second。这些数据成员用于存储时钟的小时、分钟和秒。
    • 由于它们是私有的(private),所以只能在Clock类的内部被访问和修改。这有助于封装数据并确保数据的完整性。
  • 函数成员(Function Members):
    • 函数成员是类中可以执行的操作或行为。在上述代码中,Clock 类有四个公有函数成员:一个构造函数、一个默认构造函数、一个设置时间的方法和一个显示时间的方法。
      • public Clock(int newH, int newM, int newS); // 构造函数,用于初始化时钟的时间
      • public Clock(); // 默认构造函数,如果没有提供参数,则使用默认时间(0:0:0)初始化时钟
      • public void setTime(int newH = 0, int newM = 0, int newS = 0); // 设置时间的方法,允许用户更改时钟的时间。参数有默认值,因此可以部分或完全不提供参数。
      • public void showTime(); // 显示时间的方法,将时钟的当前时间打印到控制台
    • 由于这些函数成员是公有的(public),所以它们可以在Clock类的外部被访问和使用。这允许用户与类进行交互并操作类的数据成员。

🐋4.5 类的组合程序

🧩题目

构造线段类。

📇算法思路

根据小学课本定义,线段:直线上两个点和它们之间的部分叫做线段,这两个点叫做线段的端点。因此类中包含端点(point)与连接它们的直线(line)。

⌨️算法代码

#include <iostream>  
#include <cmath> 
using namespace std;

class Point {   // 类Point的定义
public:         // 公有成员,外部接口
    Point(int newX, int newY) : x(newX), y(newY) {} // 构造函数:接受两个参数 newX、newY,分别赋值给 x、y
    Point() : x(0), y(0) {}                         // 默认构造函数:如果没有特别指定x、y的值,那么它们将默认被设置为0  
    Point(const Point& p);                          // 复制构造函数:复制类 接受 原有类 的参数p.x、p.y,并分别赋值给 x、y
    int getX() const { return x; }                  // 类成员函数:获得 x 的值
    int getY() const { return y; }                  // 类成员函数:获得 y 的值
private:        // 私有成员,类内可见
    int x, y;   // 点的 x、y 坐标
};

// 类Point 的复制构造函数
Point::Point(const Point& p) : x(p.x), y(p.y) {
    cout << "Calling the copy constructor of Point" << endl;
}

class Line {   // 类Line的定义
public:
    Line(const Point& xp1, const Point& xp2); // 构造函数:接受两个类Point(点)xp1、xp2 对象作为常量引用  
    Line(const Line& l);                      // 复制构造函数:传递Line(线段)对象作为引用  
    double getLen() const { return len; }     // 类成员函数:获得线段长度 len 的值
private:              // 私有成员,类内可见
    Point p1, p2;     // 线段的端点 p1, p2
    double len;       // 线段的长度 len
};

// 类Line 的构造函数
Line::Line(const Point& xp1, const Point& xp2) : p1(xp1), p2(xp2) {
    cout << "Calling constructor of Line" << endl;
    double dx = static_cast<double>(p1.getX() - p2.getX());
    double dy = static_cast<double>(p1.getY() - p2.getY());
    len = sqrt(dx * dx + dy * dy);
}

// 类Line 的复制构造函数
Line::Line(const Line& l) : p1(l.p1), p2(l.p2), len(l.len) {
    cout << "Calling the copy constructor of Line" << endl;
}

int main() {
    Point myp1(1, 1), myp2(4, 5);           // 调用Point构造函数,创造Point 对象myp1, myp2 
    Line line(myp1, myp2);                  // 调用Line 构造函数,创造Line 对象 line
    Line line2(line);                       // 调用Line 构造函数,复制Line 对象 line1 至 line2
    cout << "The length of the line is: ";  // 调用Line 成员函数getLen,输出line线段长度
    cout << line.getLen() << endl;  
    cout << "The length of the line2 is: "; // 调用Line 成员函数getLen,输出line2线段长度
    cout << line2.getLen() << endl; 

    return 0; 
}

📇执行结果

📇代码解释

在创建line1时,不仅调用了Line的构造函数,而且调用了2次point 的复制构造函数,也就是说,2个点对象mypoint1、mypoint2先复制到Line中,再计算长度。

  • 备注:这一点,AI表示不理解,它认为:“Line的构造函数是通过传值方式接受这两个Point对象的,但由于您使用的是常量引用(const Point& xp1, const Point& xp2),所以实际上并没有复制这两个Point对象,而是直接使用了它们的引用。因此,在这种情况下,Point的复制构造函数不会被调用。”;
  • 但考虑到了 实际运行结果,本次确实是复制了2个点无疑,AI这次的推理是有误的。

在创建line2时,同样调用了2次point 的复制构造函数与1次line的复制构造函数。也就是在组合类复试或构造时,通常都会调用子对象的复制构造函数~

📇相关知识

类的组合

类的组合是面向对象编程中的一个重要概念,它指的是一个类中包含另一个类的对象作为其数据成员的情况。组合允许您将多个对象组合成一个更大的对象,以表示现实世界中的复杂实体。例如,如果您有一个表示汽车的类,您可能会将引擎、轮胎、座椅等其他类组合到汽车类中,以构建一个完整的汽车对象。

在类的组合中,一个类(称为组合类)通常包含对其他类(称为组件类)的对象的引用。这些组件类的对象可以是已经存在的对象,也可以在创建组合类对象时创建。

组合类的构造函数通常会接收组件类对象的引用或指针,并将其存储在组合类对象的成员变量中。这样,组合类对象就可以访问和使用这些组件类对象的功能和数据。

组合的好处是可以提高代码的模块化和可重用性。通过将功能分散到不同的类中,并将它们组合在一起,可以更容易地管理和维护代码。此外,通过使用不同的组合方式,可以创建出灵活多变的数据结构和行为。

需要注意的是,在组合中,组合类与组件类之间应该保持较低的耦合度,即它们之间的依赖关系应该尽可能简单和清晰。这样可以使得代码更加灵活、可扩展和可维护。同时,也需要注意避免循环依赖的问题,即两个类之间相互依赖导致无法正确工作的情况。

🐋4.6 前向引用

📇相关概念

前向引用(Forward Declaration)在C++中指的是在类的完整定义之前对其进行的声明。它告诉编译器这个类的名字,表明这个类将在程序的其他地方定义。前向引用的语法很简单,就是在类名前面加上“class”关键字(对于类来说)或者“struct”关键字(对于结构体来说)。

然而,前向引用只能用于指针或引用类型的成员,因为这两种类型不需要知道类的完整大小。如果你试图使用一个仅仅是前向声明的类作为值类型(比如直接作为类的成员变量),编译器将会报错,因为它不知道这个类的大小和布局。

// demo1:正确
class B;
class A {
public:
    void f(B, b);
};
class B {
public:
    void f(A, a);
};
// demo2:错误
class Fred;     // 前向引用声明
class Barney {
    Fred x;     // 错误,类Fred的声明尚不完善
};
class Fred {
    Barney y;
};

🐋4.7 结构体

🧩题目

创建结构体student,具有属性 num、name、sex、age。​

📇算法思路

——

⌨️算法代码

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

// 结构体 student
struct Student {
    int num;
    string name;
    char sex;
    int age;
};

int main()
{
    Student stu = { 97001, "Lin Lin", 'F', 19 };
    cout << "Num:" << stu.num << endl;
    cout << "Name:" << stu.name << endl;
    cout << "Sex:" << stu.sex << endl;
    cout << "Age:" << stu.age << endl;
    return 0;
}

📇执行结果

📇相关概念

结构体

是C和C++等编程语言中用于表示一组不同类型数据的数据结构。它允许您将多个不同类型的数据项组合成一个单一的复合类型,以便作为一个单元进行处理。结构体通常用于表示现实世界中的实体或概念,这些实体或概念由多个相关的属性组成。

结构体与类的关系

在C语言中,结构体只是一种数据结构,不包含函数。但在C++中,结构体与类非常相似,实际上,它们几乎是完全相同的。唯一的区别是默认的访问级别:在结构体中,如果不指定访问修饰符,则成员默认为public;而在类中,如果不指定访问修饰符,则成员默认为private。但这只是默认的行为,您可以在结构体中使用privateprotected成员,也可以在类中使用public成员。

结构体与类的关系可以总结如下:

  1. 相似性:在C++中,结构体和类都可以包含数据成员和成员函数。它们都可以有构造函数、析构函数、访问修饰符和继承关系。因此,从功能上看,结构体和类几乎是完全相同的。
  2. 访问级别的默认差异:如上所述,结构体和类在成员访问级别上有默认的差异。但这并不意味着结构体不能用于封装或隐藏数据——您可以通过在结构体中使用访问修饰符来实现这一点。
  3. 历史与用法:从历史上看,结构体最初是为了表示简单的数据结构而引入的,而类则是为了支持面向对象编程而引入的。因此,在某些编程风格或约定中,人们可能会倾向于使用结构体来表示不包含复杂行为或仅用于数据聚合的类型,而使用类来表示具有更复杂行为或需要封装的类型。然而,这并不是一个严格的规则,只是一种编程习惯。
  4. 继承与多态:结构体和类在继承和多态方面的行为是相同的。它们都可以作为基类或派生类使用,并且都支持虚函数和多态性。

🐋4.8 联合体

🧩题目

以3种方式输入学生的成绩:等级、是否通过、分数。​

📇算法思路

——

⌨️算法代码

#include <string>
#include <iostream>
using namespace std;

class ExamInfo{     // 类ExamInfo
private:            // 私有成员
    string name;    // 科目
    enum MODE{ GRADE, PASS, PERCENTAGE } mode;  // 枚举类型,用于表示成绩
    union Mark {    // 联合体:用于存储实际的成绩
        char grade; // 等级成绩(如'A', 'B', 'C'等)  
        bool pass;  // 通过/未通过状态(true表示通过,false表示未通过)  
        int percent;// 百分比分数(0-100)  
    }mark;
public:             // 公有成员
    ExamInfo(string name, char grade):name(name), mode(GRADE){ mark.grade = grade; }                // 构造函数,接受 科目,等级 为输入,并赋值为 name, mark.grade
    ExamInfo(string name, bool pass) :name(name), mode(PASS){ mark.pass = pass; }                   // 构造函数,接受 科目,通过 为输入,并赋值为 name, mark.pass
    ExamInfo(string name, int percent) :name(name), mode(PERCENTAGE){ mark.percent = percent; }     // 构造函数,接受 科目,通过 为输入,并赋值为 name, mark.percent
    
    void show();    // 成员函数,用于显示考试信息(根据成绩的表示方式输出相应的成绩信息)  
};

// 类ExamInfo成员函数
void ExamInfo::show() {
    cout << name << ":";
    switch (mode) {
    case GRADE: cout << mark.grade; break;
    case PASS:  cout << (mark.pass ? "PASS" : "FAIL"); break;
    case PERCENTAGE: cout << mark.percent << "%"; break;
    }
    cout << endl;
}

int main()
{
    ExamInfo course1("English", 'B');           // 调用构造函数,创建对象course1 科目英语, 等级B
    ExamInfo course2("Calculus", true);         // 调用构造函数,创建对象course2 科目微积分, 通过考试
    ExamInfo course3("C++ Programming", 85);    // 调用构造函数,创建对象course3 科目C++, 成绩85
    course1.show();    // 调用类成员函数,显示course1
    course2.show();    // 调用类成员函数,显示course2
    course3.show();    // 调用类成员函数,显示course3
    return 0;
}

📇执行结果

📇相关概念

联合体

在这段程序中,union(联合体)被用于Mark的定义,它的作用是允许在同一块内存区域存储不同的数据类型。具体地说,Mark联合体可以存储一个字符类型的等级成绩(grade)、一个布尔类型的通过状态(pass),或者一个整数类型的百分比分数(percent)。但是,这三个成员变量共享同一块内存,所以它们不能同时被使用或赋值;在任何时候,只有最近一次被赋值的成员变量是有效的。

🐋4.9 枚举类

⌨️算法代码

“#include <iostream>
using namespace std;

enum class Side{Right, Left };
enum class Thing{Wrong, Right };    // 不冲突

int main()
{
    Side s = Side::Right;
    Thing w = Thing::Wrong;
    // cout << (s == w) << endl;    // 编译错误,无法直接比较不同枚举类
    return 0;
}

📇代码说明

在这段代码中,定义了两个枚举类:Side 和 Thing。枚举类(也称为“强类型枚举”)是 C++11 引入的新特性,它提供了一种更加严格和类型安全的枚举方式。

  1. enum class Side{Right, Left }; 定义了一个名为 Side 的枚举类,它有两个枚举值:Right 和 Left。这些值表示某种“方向”或“侧面”。

  2. enum class Thing{Wrong, Right }; 定义了另一个名为 Thing 的枚举类,它同样有两个枚举值:Wrong 和 Right。这些值可能表示某种“事物”的“正确”或“错误”状态。

重要的是要注意,尽管 Side 和 Thing 枚举类中都有一个名为 Right 的枚举值,但它们分属于不同的枚举类,因此是不同的类型和值。在 C++ 中,不同枚举类的枚举值之间不能直接进行比较或运算,除非你显式地将它们转换为能够比较的类型(例如整数)。

🐋4.10 组合类例题

🧩题目

构造类compuper。

📇算法思路

——

⌨️算法代码

#include <iostream>
using namespace std;

enum CPU_RANK { P1 = 1, P2, P3, P4, P5, P6, P7 };
class CPU {
private:
    CPU_RANK rank;
    int frequency;
    float voltage;
public:
    // 构造函数  
    CPU(CPU_RANK r, int f, float v) : rank(r), frequency(f), voltage(v) {
        cout << "构造了一个CPU!" << endl;
    }

    // 复制构造函数  
    CPU(const CPU& other) : rank(other.rank), frequency(other.frequency), voltage(other.voltage) {
        cout << "复制构造了一个CPU!" << endl;
    }

    // 析构函数  
    ~CPU() { cout << "析构了一个CPU!" << endl; }

    // 外部接口函数
    CPU_RANK GetRank() const { return rank; }
    int GetFrequency() const { return frequency; }
    float GetVoltage() const { return voltage; }

    void SetRank(CPU_RANK r) { rank = r; }
    void SetFrequency(int f) { frequency = f; }
    void SetVoltage(float v) { voltage = v; }

    void Run() { cout << "CPU开始运行!" << endl; }
    void Stop() { cout << "CPU停止运行!" << endl; }
};

enum RAM_Type {DDR2 = 2, DDR3, DDR4};
class RAM {
private:
    enum RAM_Type type;
    unsigned int frequency;
    unsigned int size;

public:
    // 构造函数  
    RAM(RAM_Type t, unsigned int f, unsigned int s) : type(t), frequency(f), size(s) {
        cout << "构造了一个RAM!" << endl;
    }

    // 复制构造函数  
    RAM(const RAM& other) : type(other.type), frequency(other.frequency), size(other.size) {
        cout << "复制构造了一个RAM!" << endl;
    }

    // 析构函数  
    ~RAM() { cout << "析构了一个RAM!" << endl; }

    RAM_Type GetType() const { return type; }
    unsigned int GetFrequency() const { return frequency; }
    unsigned int GetSize() const { return size; }

    void SetType(RAM_Type t) { type = t; }
    void SetFrequency(int f) { frequency = f; }
    void SetSize(int s) { size = s; }

    void Run() { cout << "RAM开始运行!" << endl; }
    void Stop() { cout << "RAM停止运行!" << endl; }
};

enum CDROM_Interface { SATA, USB };
enum CDROM_Install_type {external, built_in };
class CD_ROM {
private:
    CDROM_Interface interface_type;
    unsigned int cache_size;
    CDROM_Install_type install_type;

public:
    // 构造函数  
    CD_ROM(CDROM_Interface i, unsigned int s, CDROM_Install_type it) : interface_type(i), cache_size(s), install_type(it) {
        cout << "构造了一个CD_ROM!" << endl;
    }

    // 复制构造函数  
    CD_ROM(const CD_ROM& other) : interface_type(other.interface_type), cache_size(other.cache_size), install_type(other.install_type) {
        cout << "复制构造了一个CD_ROM!" << endl;
    }

    // 析构函数  
    ~CD_ROM() { cout << "析构了一个CD_ROM!" << endl; }

    CDROM_Interface GetInterfaceType() const { return interface_type; }
    unsigned int Get_Size() const { return cache_size; }
    CDROM_Install_type GetIntallType () const { return install_type; }

    void SetInterfaceType(CDROM_Interface i) { interface_type = i; }
    void SetSize(int s) { cache_size = s; }
    void SetIntallType(CDROM_Install_type i) { install_type = i; }

    void Run() { cout << "CD_ROM开始运行!" << endl; }
    void Stop() { cout << "CD_ROM停止运行!" << endl; }
};

class COMPUTER {
private:
    CPU my_cpu;
    RAM my_ram;
    CD_ROM my_cdrom;
    unsigned int storage_size;
    unsigned int bandwidth;

public:
    // 构造函数  
    COMPUTER(CPU c, RAM r, CD_ROM cd, unsigned int s, unsigned int b);

    // 复制构造函数  
    COMPUTER(const COMPUTER& other) : my_cpu(other.my_cpu), my_ram(other.my_ram), my_cdrom(other.my_cdrom), storage_size(other.storage_size), bandwidth(other.bandwidth) {
        cout << "复制构造了一个COMPUTER!" << endl;
    }

    // 析构函数  
    ~COMPUTER() { cout << "析构了一个COMPUTER!" << endl; }

    void Run(){
        my_cpu.Run();
        my_ram.Run();
        my_cdrom.Run();
        cout << "COMPUTER开始运行!" << endl;
    }

    void Stop(){
        my_cpu.Stop();
        my_ram.Stop();
        my_cdrom.Stop();
        cout << "COMPUTER停止运行!" << endl;
    }
};

// 构造函数
COMPUTER::COMPUTER(CPU c, RAM r, CD_ROM cd, unsigned int s, unsigned int b):my_cpu(c), my_ram(r), my_cdrom(cd), storage_size(s), bandwidth(b) {
    cout << "构造了一个COMPUTER!" << endl;
}

int main()
{
    CPU a(P6, 300, 2.8);
    a.Run();
    a.Stop();
    cout << "*********************\n";

    RAM b(DDR3, 1600, 8);
    b.Run();
    b.Stop();
    cout << "*********************\n";

    CD_ROM c(SATA, 2, built_in);
    c.Run();
    c.Stop();
    cout << "*********************\n";

    COMPUTER my_computer(a, b, c, 128, 10);
    cout << "*********************\n";

    my_computer.Run();
    my_computer.Stop();
    cout << "*********************\n";

    return 0;
}

📇执行结果

📇代码解释

类的组合程序,构造类,复制构造类与4.5相似~~

在C++中,当我们创建包含其他类对象的复合类(如Computer类包含CPURAMCD_ROM类对象)时,会涉及到对象的构造和复制构造。以下是一个跟踪输出示例节选,展示了在构造Computer对象时子对象的构造和析构过程:

*********************
复制构造了一个CD_ROM!
复制构造了一个RAM!
复制构造了一个CPU!
复制构造了一个CPU!
复制构造了一个RAM!
复制构造了一个CD_ROM!
构造了一个COMPUTER!
析构了一个CPU!
析构了一个RAM!
析构了一个CD_ROM!
*********************

从输出中可以看出,在构造Computer对象之前,首先对其子对象进行了复制构造(这可能是因为它们是通过值传递或作为临时对象创建的)。然后,执行了Computer的构造函数。最后,当Computer对象被销毁时,它的子对象也被相应地析构。

话说,我本人没有看出来子对象构造2次的必要性(传参复制构造1次,调用复制构造1次),而且程序也确实使用了引用传值不应该出现重复构造的情况,暂时没有想明白这是为什么。AI回答:

  • 需要注意的是,这个输出可能反映了特定的代码实现方式,其中子对象在传递给Computer构造函数之前被复制构造了一次,然后在Computer内部又被构造了一次。这通常不是最佳实践,因为它可能导致不必要的对象复制和性能开销。
  • 理想情况下,我们应该通过引用或指针传递子对象,以避免不必要的复制。另外,如果子对象在Computer构造函数中被再次构造,那么可能存在设计上的问题或误解。通常,子对象应该在Computer的构造函数中只被构造一次。

📇相关概念

析构函数

析构函数(Destructor)是C++中的一个特殊成员函数,它的主要作用是在对象生命周期结束时自动执行一些清理操作,比如释放对象在其生命周期中申请的资源(如动态分配的内存、打开的文件句柄等)。当对象的生命周期结束时,析构函数会被自动调用。

析构函数的特点如下:

  1. 析构函数的名称是在类名前加上一个波浪符(~)构成的。
  2. 析构函数没有返回值,也没有参数,因此不能重载。
  3. 析构函数可以是虚函数,当基类的指针指向派生类对象时,可以通过虚析构函数来释放派生类对象中的资源。
  4. 当程序中创建了一个对象(在栈上或堆上)时,析构函数会在对象生命周期结束时被自动调用。对于栈上的对象,当对象离开其作用域时,析构函数会被调用;对于堆上的对象,当使用delete操作符释放对象时,析构函数会被调用。

在析构函数中,通常会编写一些释放资源的代码,以确保对象在销毁时能够正确地清理其所占用的资源,从而避免内存泄漏等问题。例如,如果一个类在构造函数中动态分配了内存,那么在析构函数中就应该释放这块内存。

需要注意的是,析构函数并不负责删除对象本身,而是负责清理对象所占用的资源。对象的删除是由操作系统或内存管理器来负责的。在C++中,当对象的生命周期结束时,析构函数会被自动调用,然后对象的内存会被释放回操作系统或内存管理器中。


🔚结语

博文到此结束,写得模糊或者有误之处,期待小伙伴留言讨论与批评,督促博主优化内容{例如有错误、难理解、不简洁、缺功能}等,博主会顶锅前来修改~~😶‍🌫️😶‍🌫️

我是梅头脑,本片博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下,感谢点赞小伙伴对于博主的支持~~🌟🌟

同系列的博文:🌸数据结构_梅头脑_的博客-CSDN博客

同博主的博文:🌸随笔03 笔记整理-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/414242.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

尚硅谷(SpringCloudAlibaba微服务分布式)学习代码Eureka部分

1.项目结构 2.cloud2024 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.a…

【C++】auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法&#xff08;C 11)1、auto 是什么&#xff1f;2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11&#xff1a; 范围 for 循环的扩展&#xff1a; 三…

MCU最小系统电路设计(以STM32F103C8T6为例)

目录 一、何为最小系统&#xff1f; 二、最小系统电路设计 1.电源 &#xff08;1&#xff09;各种名词解释 &#xff08;2&#xff09;为什么会有VDD_1 _2 _3区分&#xff1f; &#xff08;3&#xff09;Mirco USB &#xff08;4&#xff09;5v->3.3v滤波电路 &#…

尚硅谷webpack5笔记2

Loader 原理 loader 概念 帮助 webpack 将不同类型的文件转换为 webpack 可识别的模块。 loader 执行顺序 分类pre: 前置 loadernormal: 普通 loaderinline: 内联 loaderpost: 后置 loader执行顺序4 类 loader 的执行优级为:pre > normal > inline > post 。相…

算法day01_ 27. 移除元素、977.有序数组的平方

推荐阅读 从零开始学数组&#xff1a;深入浅出&#xff0c;带你掌握核心要点 初探二分法 再探二分法 系统的纪录一下刷算法的过程&#xff0c;之前一直断断续续的刷题&#xff0c;半途而废&#xff0c;现在重新开始。话不多说&#xff0c;开冲&#xff01; 27.移除元素 题目 给…

雾锁王国Enshrouded服务器CPU内存配置怎么选择?

雾锁王国/Enshrouded服务器CPU内存配置如何选择&#xff1f;阿里云服务器网aliyunfuwuqi.com建议选择8核32G配置&#xff0c;支持4人玩家畅玩&#xff0c;自带10M公网带宽&#xff0c;1个月90元&#xff0c;3个月271元&#xff0c;幻兽帕鲁服务器申请页面 https://t.aliyun.com…

php基础学习之错误处理(其一)

一&#xff0c;错误处理的概念 错误处理指的是系统(或者用户)在执行某些代码的时候&#xff0c;发现有错误&#xff0c;就会通过错误处理的形式告知程序员&#xff0c;俗称报错 二&#xff0c;错误分类 语法错误&#xff1a;书写的代码不符合 PHP 的语法规范&#xff0c;语法错…

协议-http协议-基础概念01-发展历程-http组成-http是什么-相关的应用-相关的协议

发展历程-http组成-http是什么-相关的应用-相关的协议 参考来源&#xff1a; 极客时间-透视HTTP协议(作者&#xff1a;罗剑锋)&#xff1b; 01-HTTP的发展历程 1989 年&#xff0c;任职于欧洲核子研究中心&#xff08;CERN&#xff09;的蒂姆伯纳斯 - 李&#xff08;Tim Ber…

异地文件共享慢如何解决?

如今&#xff0c;随着信息化的迅猛发展&#xff0c;异地文件共享已经成为了许多企业和个人不可或缺的一部分。在实际应用过程中&#xff0c;我们常常会遇到异地文件共享速度缓慢的问题。本文将深入探讨异地文件共享慢的原因&#xff0c;并介绍一种解决方案——天联组网&#xf…

R语言数学建模(一)—— 基础知识

R语言数学建模&#xff08;一&#xff09;—— 基础知识 文章目录 R语言数学建模&#xff08;一&#xff09;—— 基础知识前言一、建模软件1.1 软件建模的基础1.2 模型的分类1.3 不同类型模型间的联系1.4 一些术语1.5 建模如何适应数据分析过程 二、Tidyverse基础2.1 tidyvers…

【mysql】1812 - Tablespace is missing for table `job`.`xxl_job_log`.

打开表提示&#xff1a; 1812 - Tablespace is missing for table job.xxl_job_log. 1812-表“job”缺少表空间xxl_job_log。 尝试删除表重建表 DROP TABLE IF EXISTS job.xxl_job_log; 提示&#xff1a; 1051 - Unknown table job.xxl_job_log 1051-未知表“job.xxl_job_lo…

什么是去中心化云计算?

去中心化云计算是一种新型的云计算方式&#xff0c;它与传统的中心化云计算不同&#xff0c;将数据和计算任务分布到多个节点上&#xff0c;而不是将数据集中存储在中心服务器上。这种云计算方式具有许多优势&#xff0c;包括提高数据安全性、降低运营成本、增强可扩展性和灵活…

【监督学习之模型选择与评估】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱1. 模型选择&#xff1a;2. 模型评估&#xff1a;3. 超参数调优&#xff1a;4. 最终模型选择&#xff1a;实践建议&#xff1a; 详细内容总结 简述概要 了解模型选择与评估 知识图谱 在监督学习中&…

CV论文--2024.2.28

source:CV论文--2024.2.28 1、StreamDiffusion: A Pipeline-level Solution for Real-time Interactive Generation 中文标题&#xff1a;StreamDiffusion: 一个用于实时交互生成的管道级解决方案 简介&#xff1a;我们介绍了StreamDiffusion&#xff0c;这是专为实时交互式图…

RK3568平台 RTC时间框架

一.RTC时间框架概述 RTC&#xff08;Real Time Clock&#xff09;是一种用于计时的模块&#xff0c;可以是再soc内部&#xff0c;也可以是外部模块。对于soc内部的RTC&#xff0c;只需要读取寄存器即可&#xff0c;对于外部模块的RTC&#xff0c;一般需要使用到I2C接口进行读取…

prometheus+grafana监控nginx的简单实现

1.编译安装NGINX 加入编译安装nginx-module-vts模块,目的是为了获取更多的监控数据(虚拟主机&#xff0c;upstream等) nginx下载 http://nginx.org/download/nginx-1.20.2.tar.gz nginx-module-vts下载 https://github.com/vozlt/nginx-module-vts/archive/refs/tags/v0.2…

自然语言处理: 第十三章Xinference部署

项目地址: Xorbitsai/inference 理论基础 正如同Xorbits Inference&#xff08;Xinference&#xff09;官网介绍是一个性能强大且功能全面的分布式推理框架。可用于大语言模型&#xff08;LLM&#xff09;&#xff0c;语音识别模型&#xff0c;多模态模型等各种模型的推理。通…

在PyCharm中使用Git

安装Git CMD检查Git版本 打开cmd&#xff0c;输入git version&#xff0c;检查当前下载版本 配置git的user信息 在cmd中输入 git config --global user.name "用户名"git config --global user.email "用户邮箱"输入&#xff1a;git config --list&…

Linux下性能分析的可视化图表工具

1 sar 和sadf 1.1 简介 sar命令可以记录系统下的常见活动信息&#xff0c;例如CPU使用率、网络统计数据、Block I/O数据、内存使用情况 等。 sar命令的“-o [file_name]”参数可以将系统活动数据记录到file_name文件&#xff0c;然后通过sadf来解析&#xff0c;sadf命令的“-g…

音频混音算法的实现

最近项目有用到混音算法&#xff0c;这里用比较常见的一种&#xff0c;就是简单的加和之后做一下归一化。 是参考这个博主实现的&#xff1a; 音频混音的算法实现 下面直接贴代码&#xff1a; #include <stdio.h> #include <stdlib.h> #include <math.h&…