8.5 — Constructors

When all members of a class (or struct) are public, we can initialize the class (or struct) directly using an initialization list or uniform initialization (in C++11):

However, as soon as we make any member variables private, we’re no longer able to initialize classes in this way. It does make sense: if you can’t directly access a variable (because it’s private), you shouldn’t be able to directly initialize it.

So then how do we initialize a class with private member variables? The answer is through constructors.


A constructor is a special kind of class member function that is automatically called when an object of that class is instantiated. Constructors are typically used to initialize member variables of the class to appropriate default or user-provided values, or to do any setup steps necessary for the class to be used (e.g. open a file or database).

Unlike normal member functions, constructors have specific rules for how they must be named:

  1. Constructors should always have the same name as the class (with the same capitalization)
  2. Constructors have no return type (not even void)

Note that constructors are only intended to be used for initialization. You should not try to call a constructor to re-initialize an existing object. While it may compile, the results will not be what you intended (instead, the compiler will create a temporary object and then discard it).

Default constructors

A constructor that takes no parameters (or has parameters that all have default values) is called a default constructor. The default constructor is called if no user-provided initialization values are provided.

Here is an example of a class that has a default constructor:

This class was designed to hold a fractional value as an integer numerator and denominator. We have defined a default constructor named Fraction (the same as the class).

Because we’re instantiating an object of type Fraction with no arguments, the default constructor will be called immediately after memory is allocated for the object, and our object will be initialized.

This program produces the result:


Note that our numerator and denominator were initialized with the values we set in our default constructor! This is such a useful feature that almost every class includes a default constructor. Without a default constructor, the numerator and denominator would have garbage values until we explicitly assigned them reasonable values (remember: fundamental variables aren’t initialized by default).

Direct and uniform initialization using constructors with parameters

While the default constructor is great for ensuring our classes are initialized with reasonable default values, often times we want instances of our class to have specific values that we provide. Fortunately, constructors can also be declared with parameters. Here is an example of a constructor that takes two integer parameters that are used to initialize the numerator and denominator:

Note that we now have two constructors: a default constructor that will be called in the default case, and a second constructor that takes two parameters. These two constructors can coexist peacefully in the same class due to function overloading. In fact, you can define as many constructors as you want, so long as each has a unique signature (number and type of parameters).

So how do we use this constructor with parameters? It’s simple! We just use the direct initialization form of initialization:

This particular fraction will be initialized to the fraction 5/3!

In C++11, we can also use uniform initialization:

Note that we have given the second parameter of the constructor with parameters a default value, so the following is also legal:

Default values for constructors work exactly the same way as with any other function, so in the above case where we call six(6), the Fraction(int, int) function is called with the second parameter defaulted to value 1.

Rule: Use direct or uniform initialization with your classes

Copy initialization using equals with classes

Much like with fundamental variables, it’s also possible to initialize classes using copy initialization:

However, we recommend you avoid this form of initialization with classes, as it may be less efficient. Although direct initialization, uniform initialization, and copy initialization all work identically with fundamental types, copy-initialization does not work the same with classes (though the end-result is often the same). We’ll explore the differences in more detail in a future chapter.

Rule: Do not copy initialize your classes

Reducing your constructors

In the above two-constructor declaration of the Fraction class, the default constructor is actually somewhat redundant. We could simplify this class as follows:

Although this constructor is still a default constructor, it has now been defined in a way that it can accept one or two user-provided values as well.

When implementing your constructors, consider how you might keep the number of constructors down through smart defaulting of values.

A reminder about default parameters

The rules around defining and calling functions that have default parameters (described in lesson 7.7 -- Default parameters) apply to constructors too. To recap, when calling a function with default parameters, only the rightmost arguments may be defaulted.

This may product unexpected results for classes that have multiple default parameters of different types. Consider:

With s4, we’ve attempted to construct a Something by providing only a double. This won’t compile, as the rules for how arguments match with default parameters won’t allow us to skip a non-rightmost parameter (in this case, the leftmost int parameter).

If we want to be able to construct a Something with only a double, we’ll need to add a second (non-default) constructor:

An implicitly generated default constructor

If your class has no other constructors, C++ will automatically generate a public default constructor for you. This is sometimes called an implicit constructor (or implicitly generated constructor).

Consider the following class:

This class has no constructor. Therefore, the compiler will generate a constructor that behaves identically to the following:

This constructor allows us to create objects of the class, but does not do any initialization or assignment of values to the class members itself.

Although you can’t see the implicitly generated constructor, you can prove it exists:

The above code compiles, because date object will use the implicit constructor (which is public).

If your class has any other constructors, the implicitly generated constructor will not be provided. For example:

Generally speaking, it’s a good idea to always provide at least one constructor in your class. This explicitly allows you to control how objects of your class are allowed to be created, and will prevent your class from potentially breaking later when you add other constructors.

Rule: Provide at least one constructor for your class, even if it’s an empty default constructor.

Classes containing classes

A class may contain other classes as member variables. By default, when the outer class is constructed, the member variables will have their default constructors called. This happens before the body of the constructor executes.

This can be demonstrated thusly:

This prints:


When variable b is constructed, the B() constructor is called. Before the body of the constructor executes, m_a is initialized, calling the class A default constructor. This prints “A”. Then control returns back to the B constructor, and the body of the B constructor executes.

This makes sense when you think about it, as the B() constructor may want to use variable m_a -- so m_a had better be initialized first!

In the next lesson, we’ll talk about how to initialize these class member variables.

Quiz time

1) Write a class named Ball. Ball should have two private member variables with default values: m_color (“black”) and m_radius (10.0). Ball should provide constructors to set only m_color, set only m_radius, set both, or set neither value. For this quiz question, do not use default parameters for your constructors. Also write a function to print out the color and radius of the ball.

The following sample program should compile:

and produce the result:

color: black, radius: 10
color: blue, radius: 10
color: black, radius: 20
color: blue, radius: 20

Show Solution

1b) Update your answer to the previous question to use constructors with default parameters. Use as few constructors as possible.

Show Solution

2) What happens if you don’t declare a default constructor?

Show Solution

8.5a -- Constructor member initializer lists
8.4 -- Access functions and encapsulation

229 comments to 8.5 — Constructors

  • Ran

    I just stuck with the question 8.3.1.b. Following is my code.

    I thought a default constructor like this could work for all the cases.

    However, the debug just pointed out that the following code skews up
    the program.

    The complier did not act as I expected, i.e. using std::string a =
    "Black" as default value, and use 20.0 as a input double b to
    initialize the m_radius.

    In stead, we have to write a special constructor:

    This, to me, is astonishing.

    • nascardriver

      Hi Ran!

      If you have a constructor like this

      You cannot just change the order or arguments when calling it. The first argument must be a string, the second must be a double. Having a default value for the first parameter allows you to construct a Ball without passing arguments and thus using the default values.
      There is no way to explicitly use a default value unfortunately. So you either have to pass a value manually or write another constructor without the parameter you want to skip.

    • Alex

      FWIW, I've updated the lesson to talk a bit more about this.

      It's interesting to consider why C++ doesn't support default non-rightmost arguments. I suspect that it introduces ambiguity in some cases.

  • Frieder

    You might want to change the default color in your quiz description from "Black" to "black". Elsewise the output wont match the expected result. 🙂

    This is a great site. Wished I would have found it earlier to finally settle down and learn C++.

    One thing to point out is that everybody should always compare their own solution against yours. Sometimes there are hidden gems in your solution that make it worth while to ponder over (avoiding overflows, ... ).

    BTW: I dont agree with your rule "avoid unsigned". I would rather make it mandatory to use specify both "unsigned" or "signed" (or use a specific type such as sint8_t or uint8_t) to indicate that it was given a second thought what type is being used. Simply using "int" is very often a clear indicator of "what the heck, I will think about it later" (and then you never do as we all know).


    • Alex

      Casing updated, thanks for pointing out the inconsistency.

      Using unsigned numbers is fine in specific cases, but those cases are pretty specific. The Google C++ style guide says, "You should not use the unsigned integer types such as uint32_t, unless there is a valid reason such as representing a bit pattern rather than a number, or you need defined overflow modulo 2^N. In particular, do not use unsigned types to say a number will never be negative. Instead, use assertions for this."

  • JMC


    Please help. Everytime i run it, it says that i have error C3867. But i dont understand why.

    I found the error, Peluca6.print needs to be Peluca6.print()

    Meh it hurts to lose so much time in little things like this. 🙁

    • nascardriver

      Hi JMC!

      From what I understand you solved your problem? That's good. Just a two notes:

      General: Program in english and use US ASCII if you expect anyone else to be able to understand and compile your code.
      Line 5: Don't use 'using namespace'

  • ram

    Thank you
    this is very helful

  • Michael

    Hi Alex,
    The compiler gave me a type mismatch when I was doing 1) with codes below:

    It marked blue("blue") as error and said "no instance of constructor "Ball::Ball" matches the argument list argument types are:(const char [5])

    Does that mean I have to define the parameter in a C-style string way? But I think std::string should have worked just fine.
    I'm using Visual Studio Community 2017 version 15.4.3

    • Alex

      The problem here is that you've defined a bunch of constructors, but you didn't include them in the Ball class definition. The compiler should actually be complaining that the Ball constructors aren't members of the class.

      • Michael

        Thank you Alex. Solved it after moving constructors inside the class.

        I was using what VS autocomplete had given me when defining constructors.

        Every time I write a class it auto-completes into this:

        If I write my constructor in the very bottom MyClass function, the problem mentioned before will come up.
        Any idea?

        • Alex

          As long as the member functions defined outside the class (in this case, MyClass::MyClass and MyClass::~MyClass) have declarations inside the class (MyClass() and ~MyClass()), everything should work fine.

          I just realized I chat more about this in a future lesson in this chapter, but you haven't gotten there yet. Keep reading and the topic of how to define member functions outside the class will be covered.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]