Skip to the content.

第13讲 构造函数

构造函数是所有面向对象的语言都有的。C++ 的构造器和 Java 的构造器有诸多不同。
视频地址:https://www.coursera.org/learn/cpp-chengxu-sheji/lecture/8lhFP/gou-zao-han-shu

构造函数,也称「构造器」,顾名思义即用于构造(初始化)对象的函数。 1. 构造函数也是成员函数。 2. 构造函数只用与构造对象。对象生成时会调用构造函数,但对象一旦生成,并不能在其上执行构造函数。这也是构造函数和普通成员函数的区别。 3. 构造函数没有返回值,void 类型也不行。 4. 构造函数的名称和类名相同 5. 一个类可以多个构造函数 6. 如果不定义构造函数,编译器会自动生成默认的无参构造函数。如果自定义了构造函数,则将不会生成默认构造函数。

1. 默认构造函数

构造函数执行必要的初始化操作,相当于 init 函数。功能上讲,如果不定义构造函数,仅使用默认的无参构造函数,就需要定义初始化函数,对象的创建和初始化分两步走,这比只定义和使用一次构造函数要复杂,更容易引入 bug. 以下是一个调用默认构造器的例子:

class Complex {
  double real;
  double imag;

public:
  void set(double real, double imag);
}; // 编译器自动生成默认构造函数

可以通过下面两种方式使用默认构造器:

  Complex c1;                // 默认构造器被调用
  Complex *pc = new Complex; // 默认构造器被调用

(代码下载:Complex.cpp, main.cpp)

这里的构造对象的方式和 Java 的语法有些不一样,需要注意,如果是 Java,只有下面这种写法:

  Complex c1 = new Complex(); // 默认构造器被调用(Java 使用默认构造器示例)

2. 自定义构造函数

前面的 Complex 如果使用构造函数,可以改成如下形式:

class Complex {
  double real;
  double imag;

public:
  Complex(double real, double imag = 0); // 构造函数在此
};

Complex::Complex(double real, double imag) {
  this->real = real;
  this->imag = imag;
}

相应的调用语句如下:

  Complex c1(3.14);                      // 自定义构造器被调用
  Complex *pc = new Complex(2.72, 3.14); // 自定义构造器被调用

(代码下载:Complex.cpp, main.cpp)
注意上面定义构造器时,还使用了「默认参数」。实际场合中,构造函数可以定义多个。

3. 构造函数在数组中的使用

这和 Java 的语法有很大不同,下例演示(CSample.cpp):

class CSample {
  int x;

public:
  CSample() { cout << "Constructor 1 called" << endl; }
  CSample(int x) {
    this->x = x;
    cout << "Constructor 2 called" << endl;
  }
}; //这个分号必不可少!

int main() {
  CSample array1[2]; // 该数组两个元素,都使用无参构造器构造

  cout << "step1" << endl;
  CSample array2[2] = {4, 5}; // 该数组两个元素,一个用4,一个用5来作为参数构造

  cout << "step2" << endl;
  CSample array3[2] = {
      4}; // 该数组两个元素,一个用4调用调用 Constructor 2,另一个调用无参构造器

  cout << "step3" << endl;
  CSample *array4 = new CSample[2]; // 该数组两个元素,都使用无参构造器构造
  delete[] array4; // 为什么仅仅这里需要执行 delete,而 array1 ~ array3 并不需要?答:用 new 生成的对象的清理需要用户显式执行 delete 操作。

  return 0;
}

输出:

Constructor 1 called
Constructor 1 called
step1
Constructor 2 called
Constructor 2 called
step2
Constructor 2 called
Constructor 1 called
step3
Constructor 1 called
Constructor 1 called

以上代码,特别需要注意的是:

  CSample array2[2] = {4, 5}; // 该数组两个元素,一个用4,一个用5来作为参数构造

  CSample array2[2] = {CSample(4), CSample(5)}; // 该数组两个元素,一个用4,一个用5来作为参数构造

的简写形式(实际上调用了类型转换构造函数)。
还需要注意 array4 的创建:

  CSample *array4 = new CSample[2];

这里使用了 new 运算符,C++ 的 new 运算符返回的是指针。

下面再举一个简单例子(Hello.cpp):

class Hello {
public:
  Hello(int n);        // constructor 1
  Hello(int n, int m); // constructor 2
  Hello();             // constructor 3
};

Hello::Hello(int n) { cout << "Constructor 1 called" << endl; }

Hello::Hello(int n, int m) { cout << "Constructor 2 called" << endl; }

Hello::Hello() { cout << "Constructor 3 called" << endl; }

int main() {
  Hello array1[3] = {1, Hello(1, 2)};
  cout << "---------" << endl;
  Hello array2[3] = {Hello(2, 3), Hello(1, 2), 1};
  cout << "---------" << endl;
  Hello *pArray[3] = {new Hello(4), new Hello(1, 2)};
  return 0;
}

输出:

Constructor 1 called
Constructor 2 called
Constructor 3 called
---------
Constructor 2 called
Constructor 2 called
Constructor 1 called
---------
Constructor 1 called
Constructor 2 called

以上特别需要注意的是,*pArray 只生成了两个对象。


<Previous | Home | Next>