【C++构造函数与析构函数】

简介: 【C++构造函数与析构函数】

❀构造函数

我们先来看原始的Date类:

class Date {
public:
  void Init(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void Print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  d1.Init(2023, 4, 25);
  d1.Print();
  Date d2;
  d2.Init(2022, 4, 25);
  d2.Print();
  return 0;
}

上面的Date类实现中,每创建一个对象就得对对象Init一次,这样就显得很麻烦,而且我们还经常会忘记初始化。那么有没有什么办法能够不用每次都Init呢?答案是有的,那就是我们今天所要介绍的主题【构造函数】。


构造函数是一个特殊的成员函数,他的名字和类的名字相同,创建类的对象的时候编译器会自动调用该函数,以保证对每个数据成员都有初始值,并且在整个对象生命周期中只出现一次。


构造函数的特性

构造函数是特殊的成员函数,虽然名字叫做构造函数,但他的任务可不是为对象创建而开空间,他的主要任务是初始化对象


特征:

  1. 函数名与类名相同。
  2. 无返回值(也不需要写void)
  3. 对象实例化的时候编译器会自动调用对应的构造函数。
  4. 构造函数可以重载。
class Date
{
public:
  // 1.无参构造函数
  Date()
  {}
  // 2.带参构造函数
  Date(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1; // 调用无参构造函数
  Date d2(2015, 1, 1); // 调用带参的构造函数
  // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
  // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
  // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
  Date d3();
  return 0;
}

5. 如果类中没有显示定义构造函数,则C++编译器会自动生成一个午餐的默认构造函数,一旦用户显示定义百年一起将不再生成。

class Date
{
public:
  // 如果用户显式定义了构造函数,编译器将不再生成
  void Print()
  {
    cout << _year << "-" <<_month << "-" << _day << endl;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  d1.Print();
  return 0;
}

690ea795086d47c380e96c0e1c991f70.png

我们可以看到自动生成无参的默认构造函数,并没有对变量进行初始化,打印出来的是随机值。


6.我们不写,编译器自动生成的默认构造函数,内置类型不做处理,自定义类型会去调用他自己的默认构造。

1.内置类型/基本类型,语言本身定义的基础类型例如:char/int/double/指针变量等。

2.自定义类型。(struct/class等定义的类型)

3.有些编译器会自己也会处理内置类型,但那是个性化行为,并不是所有的编译器都会处理。

【注意】:C++11中针对内置类型成员不初始化的缺陷,又打了个补丁,即:内置类型成员变量在类中声明时可以给默认值。


class Date
{
public:
  // 如果用户显式定义了构造函数,编译器将不再生成
    Date(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void Print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
private:
  int _year=2023;
  int _month=4;
  int _day=28;
};
int main()
{
  Date d1;
  d1.Print();
  return 0;
}

c78113466af247f5b57dc87aef30ecc7.png

7.无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能由一个。

【注意】:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。

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

上面的代码编译时会报错>

d62e56ec9ae24c219cace2f4473c0d57.png

  1. 因为创建d1对象的时候要调用构造函数,这时候类里面的两个构造函数都可以不传参,这时候编译器就不知道要调用那个构造函数。

总结:
一般情况下,有内置类型成员,就要自己写构造函数,不能使用编译器自己生成的。
全部是自定义类型时,可以考虑让编译器自己生成。


❀析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

析构函数的特性

析构函数是特殊的成员变量。


特征:

  1. 析构函数名是在类名前面加上字符~。
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数,如果没有自己定义析构函数,那么系统会自动生成默认的析构函数。
    【注意】:析构函数不能重载。


4.对象生命周期结束时,C++编译系统会自动调用析构函数。


typedef int DataType;
class Stack
{
public:
  Stack(size_t capacity = 3)
  {
    cout << "Stack()" << endl;
    _array = (DataType*)malloc(sizeof(DataType) * capacity);
    if (NULL == _array)
    {
      perror("malloc申请空间失败!!!");
      return;
    }
    _capacity = capacity;
    _size = 0;
  }
  void Push(DataType data)
  {
    // CheckCapacity();
    _array[_size] = data;
    _size++;
  }
  // 析构函数
  ~Stack()
  {
    cout << "~Stack()" << endl;
    if (_array)
    {
      free(_array);
      _array = NULL;
      _capacity = 0;
      _size = 0;
    }
  }
private:
  DataType* _array;
  int _capacity;
  int _size;
};
int main()
{
  Stack s;
  s.Push(1);
  return 0;
}

0edf4181f7c64af6b443f941a159f575.png

  1. 系统生成的析构函数对内置成员不做处理,自定义类型会去调用它的析构函数。

总结:


3c80fa2f90494fd3b9fa01a71ac1ee4e.png

🍀小结🍀

今天我们学习了构造函数和析构函数相关的细节相信大家看完有一定的收获。



相关文章
|
15天前
|
C++ 容器
【C++】拷贝构造函数、拷贝赋值函数与析构函数
【C++】拷贝构造函数、拷贝赋值函数与析构函数
65 6
|
14天前
|
安全 编译器 C++
C++一分钟之-构造函数与析构函数
【6月更文挑战第20天】C++中的构造函数初始化对象,析构函数负责资源清理。构造函数有默认、参数化和拷贝形式,需注意异常安全和成员初始化。析构确保资源释放,避免内存泄漏,要防止重复析构。示例代码展示了不同构造函数和析构函数的调用情况。掌握构造和析构是有效管理对象生命周期和资源的关键。
25 2
|
3天前
|
编译器 C++
|
6天前
|
存储 编译器 C++
【C++】类和对象④(再谈构造函数:初始化列表,隐式类型转换,缺省值
C++中的隐式类型转换在变量赋值和函数调用中常见,如`double`转`int`。取引用时,须用`const`以防修改临时变量,如`const int& b = a;`。类可以有隐式单参构造,使`A aa2 = 1;`合法,但`explicit`关键字可阻止这种转换。C++11起,成员变量可设默认值,如`int _b1 = 1;`。博客探讨构造函数、初始化列表及编译器优化,关注更多C++特性。
|
6天前
|
存储 编译器 C语言
【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)
C++类的六大默认成员函数包括构造函数、析构函数、拷贝构造、赋值运算符、取地址重载及const取址。构造函数用于对象初始化,无返回值,名称与类名相同,可重载。若未定义,编译器提供默认无参构造。析构函数负责对象销毁,名字前加`~`,无参数无返回,自动调用以释放资源。一个类只有一个析构函数。两者确保对象生命周期中正确初始化和清理。
|
10天前
|
编译器 C语言 C++
【C++】:构造函数和析构函数
【C++】:构造函数和析构函数
17 0
|
27天前
|
程序员 编译器 C++
C++中的构造函数以及默认拷贝构造函数
C++中的构造函数以及默认拷贝构造函数
10 0
|
29天前
|
编译器 C++
C++进阶之路:何为默认构造函数与析构函数(类与对象_中篇)
C++进阶之路:何为默认构造函数与析构函数(类与对象_中篇)
17 0
|
2月前
|
C++
C++ 类的初始化列表与构造函数初始化的技术性探讨
C++ 类的初始化列表与构造函数初始化的技术性探讨
14 0
|
1天前
|
编译器 C++
【C++】string类的使用④(字符串操作String operations )
这篇博客探讨了C++ STL中`std::string`的几个关键操作,如`c_str()`和`data()`,它们分别返回指向字符串的const char*指针,前者保证以&#39;\0&#39;结尾,后者不保证。`get_allocator()`返回内存分配器,通常不直接使用。`copy()`函数用于将字符串部分复制到字符数组,不添加&#39;\0&#39;。`find()`和`rfind()`用于向前和向后搜索子串或字符。`npos`是string类中的一个常量,表示找不到匹配项时的返回值。博客通过实例展示了这些函数的用法。