C++ Constructors

日月星辰 发布在Programming

default constructor

无参调用的构造函数为默认构造函数,可以是没有参数,或是所有的参数都有默认值。
什么时候需要默认构造函数?

如何创建构造函数

如果没有声明任何构造函数,编译器会帮你创建一个无参的默认构造函数。但是如果你声明了默认构造函数或是其他构造函数,编译器不再为你生成默认的构造函数。
显示地指定默认构造函数。

class SimpleClass {
  public:
     SimpleClass() = default;
     SimpleClass(double value);
}

在不需要任何构造函数,也不需要编译器生成默认构造函数时,可以显示地移除构造函数。

class SimpleClass {
  public:
     SimpleClass() = delete;
}

构造函数初始化

class SimpleClass {
  public:
     SimpleClass(double val);
    void setValue(double val) {
        mValue = val;
    }
  private:
    double mValue;
}

// 方法1
SimpleClass::SimpleClass(double val) {
  setValue(val);
}

// 方法2,使用constructor initializer
SimpleClass::SimpleClass(double val): mValue(val)
{
}

When C++ creates an object, it must create all the date members of the object before calling the constructor.
As part of creating these data members, it must call a constructor on any of them that are themselves objects. By the time you assign a value to an object inside you constructor body, you are not actually constructing that object.
You are only modifying its value.
A ctor-initializer allows you to provide initial values for data members as they are created, which is more efficient than assigning values to them later.

Several data types must be initialized in a ctor-initializer or with an in-class initializer

class Foo
{
    public:
        Foo(double value);
    private:
        double mValue;
};
Foo::Foo(double value) : mValue(value)
{
    cout << "Foo::mValue = " << mValue << endl;
}
class MyClass
{
    public:
        MyClass(double value);
    private:
        double mValue; // 注意顺序
        Foo mFoo;  // 注意顺序
};

MyClass::MyClass(double value) : mValue(value), mFoo(mValue)
{
    cout << "MyCalss::mValue = " << mValue << endl;
}
// 初始化对象
MyClass instance(1.2);
// Out put
Foo::mValue = 1.2
MyClass::mValue = 1.2

// 调整下 mValue 和 mFoo的顺序
// Out put
Foo::mValue = -9.25596e+61
MyClass::mValue = 1.2

The data members are initialized in the order they appear in the definition of the class, not the order in the ctor-initializer!

Copy Constructor

It allows you to create an object that is an exact copy of another object.
If you donnot write a copy constructor, C++ generates one for you.

When the Copy Constructor Is Called

The default semantics for passing arguments to functions in C++ is pass-by-value.

For performance reasons, it is best to pass objects by const reference instead of value.

可以显示 指定或删除copy constructor.

SimpleClass(const SimpleClass& src) = default;
// or
SimpleClass(const SimpleClass& src) = delete;

Initializer-list Constructors

An initializer-list constructor is a constructor with an std::initializer_list<T> as first parameter, without any additional parameters or with additional parameters having default values.

You need to include the <initializer_list> header.

class EvenSequence
{
    public:
        EvenSequence(initializer_list<double> args)
        {
            if (args.size() % 2 != 0) {
                throw invalid_argument("initializer_list should contain even number of elements.");
            }
            mSequence.assign(args);
        }
    private:
        vector<double> mSequence;
};
// Example
EvenSequence p1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};

The Standard Library has full support for initializer-list constructors. For example:

// with initializer-list constructors
std::vector<std::string> v = {"string 1", "string 2", "string 3"};

// without initializer-list constructors
std::vector<std::string> v;
v.push_back("string 1");
v.push_back("string 2");
v.push_back("string 3");

Delegating Constructor

Delegating constructors allow constructors to call another constructor from the same class.

Make sure you avoid constructor recursion while using delegate constructor.

class MyClass
{
    MyClass(char c) : MyClass(1.2) { }
    MyClass(double d) : MyClass('m') { }
};

Move Constructor