在 C++ 中实现类构造函数

Jinku Hu 2023年10月12日
  1. 什么是构造函数以及它们如何在 C++ 中工作
  2. 在 C++ 中使用重载实现多个类构造函数
在 C++ 中实现类构造函数

本文将介绍如何在 C++ 中实现类构造函数。

什么是构造函数以及它们如何在 C++ 中工作

构造函数是定义类对象应该如何初始化的特殊成员函数。构造函数通常初始化类的数据成员,并在创建类对象时执行它们。构造函数的一些特定特性是它们与类本身具有相同的名称并且不能具有返回类型。通常,一个类具有多个相互重载的构造函数,但它们必须具有不同数量或类型的参数。

请注意,构造函数通常由用户在任何稍微复杂的类中明确指定。尽管如此,当用户没有定义任何构造函数时,编译器会自动生成默认构造函数。默认构造函数通常是不带参数的构造函数,它被调用用于类的默认初始化。但是请注意,编译器生成的默认构造函数正式称为合成默认构造函数。后者是专门为每个类根据其数据成员推断出来的,它使用类内初始化器或使用默认值来初始化成员。因此,自动生成的构造函数不是通用的解决方案,但它们对于简单的类结构可以正常工作。

在下面的示例中,我们定义了一个带有两个构造函数的 MyClass1 类。请注意,第一个不带任何参数,这意味着它是一个默认构造函数,但我们仍然指定了一个 default 关键字。后者向编译器指示此特定构造函数应为默认构造函数。通常,如果用户定义了任何构造函数,编译器不会生成默认构造函数。在这种情况下,用户应该明确要求为给定的构造函数指定 default

MyClass1 的第二个构造函数将单个 string 值作为参数并用它初始化 name 数据成员。它将特殊字符串文字打印到 cout 流,只是为了使函数执行时刻可见以供观察。m2 对象创建触发构造函数一。m1 对象使用默认构造函数初始化,由于编译器本身生成后一个,我们在 cout 流上看不到任何打印字符串。

#include <iostream>
#include <utility>

using std::cout;
using std::endl;
using std::string;

class MyClass1 {
 private:
  string name;
  string nickname;

 public:
  MyClass1() = default;
  explicit MyClass1(string n) : name(std::move(n)) {
    cout << "Constructor 1 is called" << endl;
  };

  string getName() { return name; }

  string getNickname() { return nickname; }

  ~MyClass1() { cout << "Destructor is called" << endl; }
};

int main() {
  MyClass1 m1{};
  cout << m1.getName() << endl;
  cout << m1.getNickname() << endl;
  cout << "------------------" << endl;

  string n1("Maude");
  MyClass1 m2(n1);
  cout << m2.getName() << endl;
  cout << m2.getNickname() << endl;
  cout << "------------------" << endl;

  return EXIT_SUCCESS;
}

输出:

------------------
Constructor 1 is called
Maude

------------------
Destructor is called
Destructor is called

在 C++ 中使用重载实现多个类构造函数

MyClass1 具有名为 nickname 的第二个 string 数据成员。假设我们创建了另一个构造函数,它接受单个 string 值并定义它来初始化 nickname。在这种情况下,编译器将引发错误,即我们无法重载具有相同参数的函数。因此,我们需要定义另一个构造函数,例如,我们选择了接受两个 string 引用并初始化两个数据成员的构造函数。当下面的代码片段运行时,我们可以看到第二个构造函数被执行了。

构造函数有更详细的特性,我们在本文中只介绍了主要特性。其他特殊函数的名称中包含单词 - constructor,例如 move-constructor 和 copy-constructor。这两个是统称为复制控制的特殊操作的一部分。请注意,析构函数的行为与构造函数的行为相反。即,它们释放类成员,并且通常在对象超出范围时自动调用它们。可以使用给定的代码片段轻松观察构造函数-析构函数调用行为。

#include <iostream>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::string;

class MyClass1 {
 private:
  string name;
  string nickname;

 public:
  MyClass1() = default;
  explicit MyClass1(string n) : name(std::move(n)) {
    cout << "Constructor 1 is called" << endl;
  };

  // ERROR: Does not Compile
  //    MyClass1(string nk) : nickname(nk) {
  //        cout << "Constructor 3 is called" << endl;
  //    };
  MyClass1(string &n, string &nk) : name(n), nickname(nk) {
    cout << "Constructor 2 is called" << endl;
  };

  string getName() { return name; }

  string getNickname() { return nickname; }

  ~MyClass1() { cout << "Destructor is called" << endl; }
};

int main() {
  string n1("Maude");
  string n2("Bibi");

  MyClass1 m4(n1, n2);
  cout << m4.getName() << endl;
  cout << m4.getNickname() << endl;
  cout << "------------------" << endl;

  return EXIT_SUCCESS;
}

输出:

Constructor 2 is called
Maude
Bibi
------------------
Destructor is called
Destructor is called
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C++ Class