构造器概述

构造函数(constructor)用于自定义如何初始化类成员,或在创建类的对象时调用函数。构造函数与类同名,没有返回值。可以根据需要定义任意多个重载构造函数,以各种方式自定义初始化。通常定义构造函数访问权限为public,以便类定义或继承层次结构之外的代码可以创建类对象。但也可以将构造函数声明为protectedprivate

  • 构造器可以声明为inline、explicit、friendconstexpr
  • 构造器可以初始化声明为const/volatile/const volatile的对象。这些对象在构造器完成后成为const(举例)
  • 在源文件中定义构造器,给它一个与任何其他成员函数一样的限定名,比如Box::Box(){...}

当声明类实例时,编译器根据重载解析规则(the rules of overload resolution)选择要调用的构造函数

int main()
{
    Box b; // Calls Box()

    // Using uniform initialization (preferred):
    Box b2 {5}; // Calls Box(int)
    Box b3 {5, 8, 12}; // Calls Box(int, int, int)

    // Using function-style notation:
    Box b4(2, 4, 6); // Calls Box(int, int, int)
}

成员初始化列表

构造函数可以设置成员初始化列表(member initializer list),在执行构造函数体之前初始化类成员,这是一种更有效的初始化类成员的方法

class Box {
public:
    Box(int width, int height, int length) : m_width(width), m_height(height) {
        this->m_length = length;
    }

private:
    int m_width;
    int m_height;
    int m_length;
};

注意:const和引用类型成员必须在成员初始化列表中初始化

应该在初始值列表中调用参数化基类构造函数,以确保在执行派生构造函数之前基类已完全初始化

class Base {
public:
    Base(int length) : length(length) {}

private:
    const int length;
};

class Box : public Base {
public:
    Box(int width, int height, int length) : Base(length), m_width(width), m_height(height) {}

private:
    int m_width;
    int m_height;
};

内容列表

下文可分为:

  1. 默认构造器
  2. 复制构造器
  3. 移动构造器
  4. 构造器执行顺序
  5. 构造器的继承
  6. 构造器和复合类

默认构造器

默认构造器通常指的是没有参数的构造器,或者所有参数都有默认值的构造器

如果定义类时没有声明构造器,那么编译器会提供一个隐式inline默认构造器,也可以自定义默认构造器

Box() { /*perform any required default initialization steps*/}
# 或者设置默认值
// All params have default values
Box (int w = 1, int l = 1, int h = 1): m_width(w), m_height(h), m_length(l){}

只要类声明了构造器,那么编译器不会再提供了默认构造器了

可以删除默认构造器,

  • 如果没有其他构造器,那么定义类对象时会报错
  • 如果一个类没有默认的构造函数,则不能使用方括号语法单独构造该类的对象数组
Box() = delete;
# 调用报错
Box box; # error: use of deleted function ‘Box::Box()’
# 无法使用方括号语法定义类数组
Box box[3]; # error: use of deleted function ‘Box::Box()’

复制构造器

。。。

移动构造器

。。。

显式默认和删除的构造函数

。。。

构造器执行顺序

  1. 按顺序调用基类和成员构造函数
  2. 如果类派生自虚拟基类,初始化对象的虚拟基指针
  3. 如果类具有或继承虚拟函数,则初始化对象的虚拟函数指针。虚拟函数指针指向类的虚拟函数表,以启用对代码的虚拟函数调用的正确绑定
  4. 执行函数体代码

测试代码如下:

#include <iostream>

using namespace std;

class Contained1 {
public:
    Contained1() { cout << "Contained1 ctor\n"; }
};

class Contained2 {
public:
    Contained2() { cout << "Contained2 ctor\n"; }
};

class Contained3 {
public:
    Contained3() { cout << "Contained3 ctor\n"; }
};

class BaseContainer {
public:
    BaseContainer() { cout << "BaseContainer ctor\n"; }
private:
    Contained1 c1;
    Contained2 c2;
};

class DerivedContainer : public BaseContainer {
public:
    DerivedContainer() : BaseContainer() { cout << "DerivedContainer ctor\n"; }
private:
    Contained3 c3;
};

int main() {
    DerivedContainer dc;
}
  1. 调用类DerivedContainer的基类BaseContainer的构造器
  2. 调用类BaseContainer的成员构造器Contained1Contained2
  3. 执行类Contained1和类Contained2的构造器函数体
  4. 执行类BaseContainer的构造器函数体
  5. 调用类DerivedContainer的成员构造器Container3
  6. 执行类Contained3的构造器函数体
  7. 执行类DerivedContainer的构造器函数体
Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor

继承构造器

这是c++11的新特性,使用using关键字即可从基类继承构造器

class Base
{
public:
    Base() { cout << "Base()" << endl; }
    Base(const Base& other) { cout << "Base(Base&)" << endl; }
    explicit Base(int i) : num(i) { cout << "Base(int)" << endl; }
    explicit Base(char c) : letter(c) { cout << "Base(char)" << endl; }

private:
    int num;
    char letter;
};

class Derived : Base
{
public:
    // Inherit all constructors from Base
    using Base::Base;

private:
    // Can't initialize newMember from Base constructors.
    int newMember{ 0 };
};