Edit

Share via


Constructors (C++)

To customize how a class initializes its members, or to invoke functions when an object of your class is created, define a constructor. A constructor has the same name as the class and no return value. You can define as many overloaded constructors as needed to customize initialization in various ways. Typically, constructors have public accessibility so that code outside the class definition or inheritance hierarchy can create objects of the class. But you can also declare a constructor as protected or private.

Constructors can optionally take a member initializer list. It's a more efficient way to initialize class members than assigning values in the constructor body. The following example shows a class Box with three overloaded constructors. The last two use member init lists:

class Box {
public:
    // Default constructor
    Box() {}

    // Initialize a Box with equal dimensions (i.e. a cube)
    explicit Box(int i) : m_width(i), m_length(i), m_height(i) // member init list
    {}

    // Initialize a Box with custom dimensions
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}

    int Volume() { return m_width * m_length * m_height; }

private:
    // Will have value of 0 when default constructor is called.
    // If we didn't zero-init here, default constructor would
    // leave them uninitialized with garbage values.
    int m_width{ 0 };
    int m_length{ 0 };
    int m_height{ 0 };
};

When you declare an instance of a class, the compiler chooses which constructor to invoke based on 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)
}
  • Constructors may be declared as inline, explicit, friend, or constexpr.
  • A constructor can initialize an object that has been declared as const, volatile or const volatile. The object becomes const after the constructor completes.
  • To define a constructor in an implementation file, give it a qualified name like any other member function: Box::Box(){...}.

Member initializer lists

A constructor can optionally have a member initializer list, which initializes class members before the constructor body runs. (A member initializer list isn't the same thing as an initializer list of type std::initializer_list<T>.)

Prefer member initializer lists over assigning values in the body of the constructor. A member initializer list directly initializes the members. The following example shows the member initializer list, which consists of all the identifier(argument) expressions after the colon:

    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}

The identifier must refer to a class member; it's initialized with the value of the argument. The argument can be one of the constructor parameters, a function call or a std::initializer_list<T>.

const members and members of reference type must be initialized in the member initializer list.

To ensure base classes are fully initialized before the derived constructor runs, call any parameterized base class constructors in the initializer list.

Default constructors

Default constructors typically have no parameters, but they can have parameters with default values.

class Box {
public:
    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){}
...
}

Default constructors are one of the special member functions. If no constructors are declared in a class, the compiler provides an implicit inline default constructor.

#include <iostream>
using namespace std;

class Box {
public:
    int Volume() {return m_width * m_height * m_length;}
private:
    int m_width { 0 };
    int m_height { 0 };
    int m_length { 0 };
};

int main() {
    Box box1; // Invoke compiler-generated constructor
    cout << "box1.Volume: " << box1.Volume() << endl; // Outputs 0
}

If you rely on an implicit default constructor, be sure to initialize members in the class definition, as shown in the previous example. Without those initializers, the members would be uninitialized and the Volume() call would produce a garbage value. In general, it's good practice to initialize members in this way even when not relying on an implicit default constructor.

You can prevent the compiler from generating an implicit default constructor by defining it as deleted:

    // Default constructor
    Box() = delete;

A compiler-generated default constructor will be defined as deleted if any class members aren't default-constructible. For example, all members of class type, and their class-type members, must have a default constructor and destructors that are accessible. All data members of reference type and all const members must have a default member initializer.

When you call a compiler-generated default constructor and try to use parentheses, a warning is issued:

class myclass{};
int main(){
myclass mc();     // warning C4930: prototyped function not called (was a variable definition intended?)
}

This statement is an example of the "Most Vexing Parse" problem. You could interpret myclass md(); either as a function declaration or as the invocation of a default constructor. Because C++ parsers favor declarations over other things, the expression is treated as a function declaration. For more information, see Most Vexing Parse.

If any non-default constructors are declared, the compiler doesn't provide a default constructor:

class Box {
public:
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height){}
private:
    int m_width;
    int m_length;
    int m_height;

};

int main(){

    Box box1(1, 2, 3);
    Box box2{ 2, 3, 4 };
    Box box3; // C2512: no appropriate default constructor available
}

If a class has no default constructor, an array of objects of that class can't be constructed by using square-bracket syntax alone. For example, given the previous code block, an array of Boxes can't be declared like this:

Box boxes[3]; // C2512: no appropriate default constructor available

However, you can use a set of initializer lists to initialize an array of Box objects:

Box boxes[3]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };

For more information, see Initializers.

Copy constructors

A copy constructor initializes an object by copying the member values from an object of the same type. If your class members are all simple types such as scalar values, the compiler-generated copy constructor is sufficient and you don't need to define your own. If your class requires more complex initialization, then you need to implement a custom copy constructor. For example, if a class member is a pointer then you need to define a copy constructor to allocate new memory and copy the values from the other's pointed-to object. The compiler-generated copy constructor simply copies the pointer, so that the new pointer still points to the other's memory location.

A copy constructor may have one of these signatures:

    Box(Box& other); // Avoid if possible--allows modification of other.
    Box(const Box& other);
    Box(volatile Box& other);
    Box(volatile const Box& other);

    // Additional parameters OK if they have default values
    Box(Box& other, int i = 42, string label = "Box");

When you define a copy constructor, you should also define a copy assignment operator (=). For more information, see Assignment and Copy constructors and copy assignment operators.

You can prevent your object from being copied by defining the copy constructor as deleted:

    Box (const Box& other) = delete;

Attempting to copy the object produces error C2280: attempting to reference a deleted function.

Move constructors

A move constructor is a special member function that moves ownership of an existing object's data to a new variable without copying the original data. It takes an rvalue reference as its first parameter, and any later parameters must have default values. Move constructors can significantly increase your program's efficiency when passing around large objects.

Box(Box&& other);

The compiler chooses a move constructor when the object is initialized by another object of the same type, if the other object is about to be destroyed and no longer needs its resources. The following example shows one case when a move constructor is selected by overload resolution. In the constructor that calls get_Box(), the returned value is an xvalue (eXpiring value). It's not assigned to any variable and is therefore about to go out of scope. To provide motivation for this example, let's give Box a large vector of strings that represent its contents. Rather than copying the vector and its strings, the move constructor "steals" it from the expiring value "box" so that the vector now belongs to the new object. The call to std::move is all that's needed because both vector and string classes implement their own move constructors.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Box {
public:
    Box() { std::cout << "default" << std::endl; }
    Box(int width, int height, int length)
       : m_width(width), m_height(height), m_length(length)
    {
        std::cout << "int,int,int" << std::endl;
    }
    Box(Box& other)
       : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        std::cout << "copy" << std::endl;
    }
    Box(Box&& other) : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        m_contents = std::move(other.m_contents);
        std::cout << "move" << std::endl;
    }
    int Volume() { return m_width * m_height * m_length; }
    void Add_Item(string item) { m_contents.push_back(item); }
    void Print_Contents()
    {
        for (const auto& item : m_contents)
        {
            cout << item << " ";
        }
    }
private:
    int m_width{ 0 };
    int m_height{ 0 };
    int m_length{ 0 };
    vector<string> m_contents;
};

Box get_Box()
{
    Box b(5, 10, 18); // "int,int,int"
    b.Add_Item("Toupee");
    b.Add_Item("Megaphone");
    b.Add_Item("Suit");

    return b;
}

int main()
{
    Box b; // "default"
    Box b1(b); // "copy"
    Box b2(get_Box()); // "move"
    cout << "b2 contents: ";
    b2.Print_Contents(); // Prove that we have all the values

    char ch;
    cin >> ch; // keep window open
    return 0;
}

If a class doesn't define a move constructor, the compiler generates an implicit one if there's no user-declared copy constructor, copy assignment operator, move assignment operator, or destructor. If no explicit or implicit move constructor is defined, operations that would otherwise use a move constructor use the copy constructor instead. If a class declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted.

An implicitly declared move constructor is defined as deleted if any members that are class types lack a destructor or if the compiler can't determine which constructor to use for the move operation.

For more information about how to write a non-trivial move constructor, see Move Constructors and Move Assignment Operators (C++).

Explicitly defaulted and deleted constructors

You can explicitly default copy constructors, default constructors, move constructors, copy assignment operators, move assignment operators, and destructors. You can explicitly delete all of the special member functions.

class Box2
{
public:
    Box2() = delete;
    Box2(const Box2& other) = default;
    Box2& operator=(const Box2& other) = default;
    Box2(Box2&& other) = default;
    Box2& operator=(Box2&& other) = default;
    //...
};

For more information, see Explicitly Defaulted and Deleted Functions.

constexpr constructors

A constructor may be declared as constexpr if

  • it's either declared as defaulted or else it satisfies all the conditions for constexpr functions in general;
  • the class has no virtual base classes;
  • each of the parameters is a literal type;
  • the body isn't a function try-block;
  • all non-static data members and base class subobjects are initialized;
  • if the class is (a) a union having variant members, or (b) has anonymous unions, only one of the union members is initialized;
  • every non-static data member of class type, and all base-class subobjects have a constexpr constructor

Initializer list constructors

If a constructor takes a std::initializer_list<T> as its parameter, and any other parameters have default arguments, that constructor is selected in overload resolution when the class is instantiated through direct initialization. You can use the initializer_list to initialize any member that can accept it. For example, assume the Box class (shown previously) has a std::vector<string> member m_contents. You can provide a constructor like this:

    Box(initializer_list<string> list, int w = 0, int h = 0, int l = 0)
        : m_contents(list), m_width(w), m_height(h), m_length(l)
{}

And then create Box objects like this:

    Box b{ "apples", "oranges", "pears" }; // or ...
    Box b2(initializer_list<string> { "bread", "cheese", "wine" }, 2, 4, 6);

Explicit constructors

If a class has a constructor with a single parameter, or if all parameters except one have a default value, the parameter type can be implicitly converted to the class type. For example, if the Box class has a constructor like this:

Box(int size): m_width(size), m_length(size), m_height(size){}

It's possible to initialize a Box like this:

Box b = 42;

Or pass an int to a function that takes a Box:

class ShippingOrder
{
public:
    ShippingOrder(Box b, double postage) : m_box(b), m_postage(postage){}

private:
    Box m_box;
    double m_postage;
}
//elsewhere...
    ShippingOrder so(42, 10.8);

Such conversions can be useful in some cases, but more often they can lead to subtle but serious errors in your code. As a general rule, you should use the explicit keyword on a constructor (and user-defined operators) to prevent this kind of implicit type conversion:

explicit Box(int size): m_width(size), m_length(size), m_height(size){}

When the constructor is explicit, this line causes a compiler error: ShippingOrder so(42, 10.8);. For more information, see User-Defined Type Conversions.

Order of construction

A constructor performs its work in this order:

  1. It calls base class and member constructors in the order of declaration.

  2. If the class is derived from virtual base classes, it initializes the object's virtual base pointers.

  3. If the class has or inherits virtual functions, it initializes the object's virtual function pointers. Virtual function pointers point to the class's virtual function table to enable correct binding of virtual function calls to code.

  4. It executes any code in its function body.

The following example shows the order in which base class and member constructors are called in the constructor for a derived class. First, the base constructor is called. Then, the base-class members are initialized in the order in which they appear in the class declaration. Finally, the derived constructor is called.

#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;
}

Here's the output:

Contained1 ctor
Contained2 ctor
BaseContainer ctor
Contained3 ctor
DerivedContainer ctor

A derived class constructor always calls a base class constructor, so that it can rely on completely constructed base classes before any extra work is done. The base class constructors are called in order of derivation—for example, if ClassA is derived from ClassB, which is derived from ClassC, the ClassC constructor is called first, then the ClassB constructor, then the ClassA constructor.

If a base class doesn't have a default constructor, you must supply the base class constructor parameters in the derived class constructor:

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

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

class StorageBox : public Box {
public:
    StorageBox(int width, int length, int height, const string label&) : Box(width, length, height){
        m_label = label;
    }
private:
    string m_label;
};

int main(){

    const string aLabel = "aLabel";
    StorageBox sb(1, 2, 3, aLabel);
}

If a constructor throws an exception, the order of destruction is the reverse of the order of construction:

  1. The code in the body of the constructor function is unwound.

  2. Base class and member objects are destroyed, in the reverse order of declaration.

  3. If the constructor is non-delegating, all fully constructed base class objects and members are destroyed. However, because the object itself isn't fully constructed, the destructor isn't run.

Derived constructors and extended aggregate initialization

If the constructor of a base class is non-public, but accessible to a derived class, then you can't use empty braces to initialize an object of the derived type under /std:c++17 mode and later in Visual Studio 2017 and later.

The following example shows C++14 conformant behavior:

struct Derived;

struct Base {
    friend struct Derived;
private:
    Base() {}
};

struct Derived : Base {};

Derived d1; // OK. No aggregate init involved.
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
               // which can call Base ctor.

In C++17, Derived is now considered an aggregate type. It means that the initialization of Base via the private default constructor happens directly, as part of the extended aggregate initialization rule. Previously, the Base private constructor was called via the Derived constructor, and it succeeded because of the friend declaration.

The following example shows C++17 behavior in Visual Studio 2017 and later in /std:c++17 mode:

struct Derived;

struct Base {
    friend struct Derived;
private:
    Base() {}
};

struct Derived : Base {
    Derived() {} // add user-defined constructor
                 // to call with {} initialization
};

Derived d1; // OK. No aggregate init involved.

Derived d2 {}; // error C2248: 'Base::Base': can't access
               // private member declared in class 'Base'

Constructors for classes that have multiple inheritance

If a class is derived from multiple base classes, the base class constructors are invoked in the order in which they're listed in the declaration of the derived class:

#include <iostream>
using namespace std;

class BaseClass1 {
public:
    BaseClass1() { cout << "BaseClass1 ctor\n"; }
};
class BaseClass2 {
public:
    BaseClass2() { cout << "BaseClass2 ctor\n"; }
};
class BaseClass3 {
public:
    BaseClass3() { cout << "BaseClass3 ctor\n"; }
};
class DerivedClass : public BaseClass1,
                     public BaseClass2,
                     public BaseClass3
                     {
public:
    DerivedClass() { cout << "DerivedClass ctor\n"; }
};

int main() {
    DerivedClass dc;
}

You should expect the following output:

BaseClass1 ctor
BaseClass2 ctor
BaseClass3 ctor
DerivedClass ctor

Delegating constructors

A delegating constructor calls a different constructor in the same class to do some of the work of initialization. This feature is useful when you have multiple constructors that all have to perform similar work. You can write the main logic in one constructor and invoke it from others. In the following trivial example, Box(int) delegates its work to Box(int,int,int):

class Box {
public:
    // Default constructor
    Box() {}

    // Initialize a Box with equal dimensions (i.e. a cube)
    Box(int i) :  Box(i, i, i)  // delegating constructor
    {}

    // Initialize a Box with custom dimensions
    Box(int width, int length, int height)
        : m_width(width), m_length(length), m_height(height)
    {}
    //... rest of class as before
};

The object created by the constructors is fully initialized as soon as any constructor is finished. For more information, see Delegating Constructors.

Inheriting constructors (C++11)

A derived class can inherit the constructors from a direct base class by using a using declaration as shown in the following example:

#include <iostream>
using namespace std;

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 };
};

int main()
{
    cout << "Derived d1(5) calls: ";
    Derived d1(5);
    cout << "Derived d1('c') calls: ";
    Derived d2('c');
    cout << "Derived d3 = d2 calls: " ;
    Derived d3 = d2;
    cout << "Derived d4 calls: ";
    Derived d4;
}

/* Output:
Derived d1(5) calls: Base(int)
Derived d1('c') calls: Base(char)
Derived d3 = d2 calls: Base(Base&)
Derived d4 calls: Base()*/

Visual Studio 2017 and later: The using statement in /std:c++17 mode and later brings into scope all constructors from the base class except ones that have an identical signature to constructors in the derived class. In general, it's best to use inheriting constructors when the derived class declares no new data members or constructors.

A class template can inherit all the constructors from a type argument if that type specifies a base class:

template< typename T >
class Derived : T {
    using T::T;   // declare the constructors from T
    // ...
};

A deriving class can't inherit from multiple base classes if those base classes have constructors that have an identical signature.

Constructors and composite classes

Classes that contain class-type members are known as composite classes. When a class-type member of a composite class is created, the constructor is called before the class's own constructor. When a contained class lacks a default constructor, you must use an initialization list in the constructor of the composite class. In the earlier StorageBox example, if you change the type of the m_label member variable to a new Label class, you must call both the base class constructor and initialize the m_label variable in the StorageBox constructor:

class Label {
public:
    Label(const string& name, const string& address) { m_name = name; m_address = address; }
    string m_name;
    string m_address;
};

class StorageBox : public Box {
public:
    StorageBox(int width, int length, int height, Label label)
        : Box(width, length, height), m_label(label){}
private:
    Label m_label;
};

int main(){
// passing a named Label
    Label label1{ "some_name", "some_address" };
    StorageBox sb1(1, 2, 3, label1);

    // passing a temporary label
    StorageBox sb2(3, 4, 5, Label{ "another name", "another address" });

    // passing a temporary label as an initializer list
    StorageBox sb3(1, 2, 3, {"myname", "myaddress"});
}

In this section

See also

Classes and structs