本篇将介绍类和对象中的重点部分,六大函数中的前四个尤为重要,所以这部分篇幅或许会有点长,所以请各位读者们耐心看完,相信看完会有不一样的收获😎

1.类的六大默认成员函数

一个类里面如果什么都没有,就被叫做空类,但是空类里并不是真的什么都没有,而是存在默认构造函数。这个默认构造函数虽然没有做任何具体的初始化操作(因为类中没有成员变量),但它满足了创建对象的基本需求

C++天使的灵动心跳代码:类和对象(中上)-LMLPHP

构造函数:主要完成初始化工作

析构函数:主要完成清理工作

拷贝构造函数:使用同类对象初始化创建对象

赋值运算符重载函数:将一个对象的值赋值给另一个同类型的对象

取地址运算符重载函数返回对象的地址或返回const对象的地址

const 取地址运算符重载函数返回 const 对象在内存中的地址

2.构造函数

其语法形式为

类名 () 
{}

🔥值得注意的是

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载
  5. 开空间释放空间特别好用,因为自动调用,不会忘记
  6. 一般不能放在私有(学单逆模式的时候是放在私有的)

2.1 默认构造函数

默认构造函数是一种特殊的构造函数,在没有显式提供初始化值的情况下,用于创建对象并进行默认的初始化。它没有参数或者所有参数都有默认值(全缺省),比如使用缺省参数就是,并且在对象整个生命周期内只调用一次

🧐为什么要有默认构造函数?

🤔为什么内置类型不用默认构造函数?

举个例子

class MyClass 
{
public:
    int num;
    // 默认构造函数
    MyClass() 
    {
        num = 0;
    }
};
int main() 
{
    MyClass obj;
    // 此时obj.num的值为0,因为默认构造函数将其初始化为0
    cout << obj.num;
    return 0;
}

这里调用的默认构造函数无参的,也可以不写 num = 0 这一条语句,只不过 num 的值就变成随机值了,也就是说如果要对对象进行操作一定要有默认构造函数显式存在,无论你赋不赋值,至少要让 num 有个值保证其处于一个确定的状态 ;反过来如果只是创建了对象的话,没有进行对象操作,那么可以不显式写默认构造函数,编译器会自动生成一个无参的默认构造函数

🔥值得注意的是:调用构造函数不传参数时不能写成MyClass obj(),只能写成 MyClass obj,因为对象后面不能跟括号,否则就成了函数声明无参的全缺省的,我们没写编译器默认生成的默认构造函数只能有一个

2.2 显式调用构造函数

显式调用构造函数主要用于精确控制对象的创建和初始化过程,当一个类有多个构造函数,且参数类型可能存在转换关系时,显式调用构造函数可以明确指定使用哪一个构造函数来创建对象,也就是带参的构造函数

举个例子

class Date
{
public:
  Date(int year, int month, int day)
  {
      _year = year;
      _month = month;
      _day = day;
  }
private:
    int _year;
    int _month;
    int _day;
};
int main() 
{
    Date d1(2024, 12, 6);
    return 0;
}

传入参数2024、12 、 6,将 d1 对象初始化为表示 2024 年 12 月 6 日这个日期

🔥值得注意的是:当在类中显式定义了其他构造函数(非默认构造函数)时,编译器仍然会生成默认构造函数,但是优先使用显式定义的构造函数

3.析构函数

其语法形式为

~类名 () 
{}

🔥值得注意的是

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数,注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

3.1 默认析构函数

对于只包含基本类型(如intdoublechar等)成员变量的类,默认析构函数虽然看起来没有做什么实际的操作,但它是整个对象销毁过程的一部分

举个例子

class Time
{
public:
	~Time()
	{
		cout << "~Time()" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

程序运行结束后输出~Time(),在 main 中根本没有直接创建 Time 类的对象,为什么最后会调用 Time 类的析构函数?

🔥总结:main 函数中并没有直接调用Time 类析构函数,而是显式调用编译器为 Date 类生成的默认析构函数

3.2 显式调用析构函数

当使用 malloc 在预先分配好的内存空间中创建对象时,就需要显式调用析构函数来进行对象销毁

#include <iostream>

class Array 
{
private:
    int* data;
    int size;

public:
    // 构造函数,用于开辟指定大小的内存空间
    Array(int n) 
    {
        size = n;
        int* data = (int*)malloc(sizeof(int) * n);
    }

    // 析构函数,用于释放构造函数中开辟的内存空间
    ~Array() 
    {
        free(data);
        data = nullptr;
    }
};

int main() 
{
    Array arr(5);
    return 0; 
}

这段代码自动调用构造函数和析构函数实现了空间创建和销毁避免忘记释放或开辟空间

🔥值得注意的是

  1. 一般情况下有动态资源申请,就需要显式写析构函数释放资源
  2. 没有动态申请,不需要写析构函数
  3. 需要释放的成员都是自定义类型,不需要写析构函数,这些成员变量所属类的析构函数会自动被调用

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

C++天使的灵动心跳代码:类和对象(中上)-LMLPHP

12-08 21:48