11.5 — Constructors

When all members of a class (or struct) are public, we can use aggregate initialization to initialize the class (or struct) directly using an initialization list or uniform initialization:

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 must have the same name as the class (with the same capitalization)
  2. Constructors have no return type (not even void)

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! Without a default constructor, the numerator and denominator would have garbage values until we explicitly assigned them reasonable values, or initialize them by other means (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 can use list or direct initialization:

As always, we prefer list initialization. We’ll discover reasons (Templates and std::initializer_list) to use direct initialization when calling constructors later in the tutorials. There is another special constructor that might make brace initialization do something different, in that case we have to use direct initialization. We’ll talk about these constructors later.

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 functions, 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.


Favor brace initialization to initialize class objects.

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.

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 10.8 -- Default arguments) apply to constructors too. To recap, when defining a function with default parameters, all default parameters must follow any non-default parameters, ie. there cannot be a non-defaulted parameters after a defaulted parameter.

This may produce 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 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 allows us to create a Date object without arguments.

This particular implicit constructor allows us to create a Date object with no arguments, but doesn’t initialize any of the members unless we create the Date object with direct- or list-initialization (because all of the members are fundamental types, and those don’t get initialized upon creation). If Date had members that are class-types themselves, for example std::string, the constructors of those members would be called automatically.

To make sure the member variables get initialized, we can initialize them at their declaration.

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

The above code compiles, because the 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:

To allow construction of a Date without arguments, either add default arguments to the constructor, add an empty default constructor, or explicitly add a default constructor:

Using = default is almost the same as adding a default constructor with an empty body. The only difference is that = default allows us to safely initialize member variables even if they don’t have an initializer:

Using = default is longer than writing a constructor with an empty body, but expresses better what your intentions are (To create a default constructor), and it’s safer. = default also works for other special constructors, which we’ll talk about in the future.


If you have constructors in your class and need a default constructor that does nothing, use = default.

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!

The difference to the last example in the previous section is that m_a is a class-type. class-type members get initialized even if we don’t explicitly initialize them.

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

Constructor notes

Many new programmers are confused about whether constructors create the objects or not. They do not -- the compiler sets up the memory allocation for the object prior to the constructor call.

Constructors actually serve two purposes. First, constructors determine who is allowed to create an object. That is, an object of a class can only be created if a matching constructor can be found.

Second, constructors can be used to initialize objects. Whether the constructor actually does an initialization is up to the programmer. It’s syntactically valid to have a constructor that does no initialization at all (the constructor still serves the purpose of allowing the object to be created, as per the above).

However, much like it is a best practice to initialize all local variables, it’s also a best practice to initialize all member variables on creation of the object. This can be done either via a constructor, or via other means we’ll show in future lessons.

Best practice

Always initialize all member variables in your objects.

Finally, constructors are only intended to be used for initialization when the object is created. 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).

Quiz time

Question #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

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

Show Solution

Question #2

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

Show Solution

11.6 -- Constructor member initializer lists
11.4 -- Access functions and encapsulation

493 comments to 11.5 — Constructors

  • yeokaiwei

    2. Quries Quiz 1B

    This is my code for 1B (edited with your solution)

    Why do we have to use const and & for std::string?

    • nascardriver

      Copying things is slow. See lesson F.7.3.

      • yeokaiwei

        1. The confusion I have is.
        Why is double m_radius{}; allowed to be passed by value?

        It doesn't explain why we have doubles are fine by value and strings use reference

        For example, the code is value for "degrees" but output is reference.

        In F7.3,
        "As mentioned in the introduction, one of the major disadvantages of pass by value is that all arguments passed by value are copied into the function parameters. When the arguments are large structs or classes, this can take a lot of time. References provide a way to avoid this penalty. When an argument is passed by reference, a reference is created to the actual argument (which takes minimal time) and no copying of values takes place. This allows us to pass large structs and classes with a minimum performance penalty."

        • nascardriver

          From F.7.3
          "When not to use pass by reference:
          - When passing fundamental types that don’t need to be modified (use pass by value).

          Copying fundamental types is faster than binding references to them. `double` is fundamental, `std::string` is not fundamental. There are some non-fundamental types that are fast to copy by design (eg. `std::string_view`), those are an exception from this rule.

          `sinOut` and `cosOut` have to be references, because the function wants to modify the caller's arguments.

          • yeokaiwei

            So, is this based on the developer's experience?

            Is this the method?
            Is it 1 of the 4 fundamental types (int, double, char, boolean)?
            Yes, pass by value.
            No, pass by reference.

            • nascardriver

              I don't understand what you're asking or trying to say

              • yeokaiwei

                It's a If-else statement to decide whether to pass by value or reference

                If (input value is int, double, char, boolean)
                   leave it as is.
                else If (input value is string, array, etc)
                   use &

                • nascardriver

                  if (type of input value is fundamental || type of input value is fast to copy by design)
                  pass by value
                  pass by const reference

                  This applies to in-parameters only. Out-parameters (Like `sinOut`) can't use pass by value.

  • yeokaiwei

    1. Quiz 1
    This is my answer for Quiz 1 before defaults

    I hope this is acceptable.

  • codeCoder

    is there a possibility to bifurcate the C++11 related features and having a separate chapter for that? I presume this would create less confusion. Just a feedback from your user.

    • nascardriver

      Learncpp is maintained to follow the latest C++ standards. No-longer-relevant code and explanations gradually get removed. By "no-longer-relevant" I mean anything that is not correct according to the current standard, or the one before that. The current standard is C++20. Anything that is not correct/best-practice according to C++17 or C++20 gets removed. There's few reason to be learning old C++. If someone wants to learn old C++, they're better of learning modern C++ first and then stop using new features.

  • codeCoder

    why are we using braces here and everywhere?

    Fraction fiveThirds{ 5, 3 };

    why not this?

    Fraction fiveThirds( 5, 3 );

    Its really irritating to see braces all the places.

  • The example near the beginning of this tutorial for default constructors:

    . . . does not compile for me on Code::Blocks. It says "‘Fraction::m_numerator’ should be initialized in the member initialization list [-Werror=effc++]" and "‘Fraction::m_denominator’ should be initialized in the member initialization list [-Werror=effc++]."

    Is this error to be expected?

    • nascardriver

      This is an expected result of your compiler configuration. You can temporarily remove -Werror or -Werror=effc++ from your compiler options to stop treating this warning as an error.

  • kiwiz

    Hello,for vs 2019,do you know why for direct initialization, there is a drop down option bar when you typing the arguments while for brace initialization, there isn't any?

  • Alexandra


    I have a dummy question. :)
    I'm a little bit confused about when it is necessary to have a default constructor and when not.

    I have this example:

    #include <iostream>

    class A {
        int m;
        A(int x) : m(x)
            std::cout << "A Constructor" << std::endl;

    class B {
        A a;
        int n;
        B(int x) : a(x + 1)
            std::cout << "B Constructor" << std::endl;
            n = a.m;

    int main() {
        B b(2.0);
        return 0;

    Why is this working just fine having no default constructor in A class, but it fails at compilation I try to do this:

    #include <iostream>

    class A {
        int m;
        A(int x) : m(x)
            std::cout << "A Constructor" << std::endl;

    class B {
        A a; // is this just an object declaration?
        int n;
        B(int x) : a(x + 1)
            std::cout << "B Constructor" << std::endl;
            n = a.m;

    int main() {
        A a; // is this an object construction + object initialization and my A class should have the default constructor?
        B b(2.0);
        return 0;

    Thank you!

    • nascardriver

      class-type objects are always initialized, you can't create them without initializing them.

      is a definition that would try to initialize `a` using its default constructor, BUT, you're initializing `a` in the member initializer list, so the default constructor isn't actually used. If you removed `a` from the member initializer list, you'd get an error.

      In you second example, you're trying to create an `a` without an initializer, ie. call the default constructor. Because you don't have a default constructor, you get an error.

  • XiangShuang

    Hi, nascardriver! This is a simple but interesting question. Code as below which is the same as yours at the begining of this chapter.

    Whether has this method called the implicitly constructor?

    • nascardriver


      This code doesn't use any constructors. `Foo` is an aggregate (Because it only has public member variables and fulfills some other conditions). Aggregates can be initialized like you did. The effect is that each element is initialized with the value provided.

      For a more detailed explanation, see

  • Andreas Krug

    could you please implement an example for public member function double getValue() in class Fraction. It is never used.

  • Karl Phazer

    One thing bothering me with construtors:

    If you want to call the default constructor you type:
    Foo foo;

    If you call a constructor that has a parameter you do it like this:
    Foo foo(type name);

    The confusing part is that typing:
    Foo foo();
    ..does not call the default constructor. Is there some reason for this?
    Does Foo foo(); do something in particular?

    Thanks! (and sorry for flooding the comment section)

    • Karl Phazer

      Found the answer for this by accident while reading on something else, but too late to delete the question.

      Foo foo(); will not call the constructor since it has the same form as a function declaration with no parameters and return type Foo. Could have figured it out myself if I hadn't been so too lazy to think it through :|

    • nascardriver

      This is one of the reasons why we say "prefer list initialization". With list initialization, you can have

  • Karl Phazer

    The lesson says:

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

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

    While the above segment somewhat clearly handles only the naming side of constructors, IMO it would be good to point out (at least somewhere) that even though their definitions have no return type nor can they have a return statement, constuctor( function)s implicitly return the actual objects. Or is it not so?

  • Mohammad

    What is the problem here?

  • Rosetastone

    In quiz question #1 part b , if we had the following instead, then would the compiler be confused about which default constructor should call?

    "  // Constructor with both color and radius parameters
            // handles no parameter, color only, and color + radius cases."
    In the quiz part, isn't "and color + radius cases." extra? as it is already mentioned

  • Compiler set aside memeory

    >>Many new programmers are confused about whether constructors create the objects or not. They do not -- the compiler sets up the memory allocation for the object prior to the constructor call.

    >>First, constructors determine who is allowed to create an object. That is, an object of a class can only be created if a matching constructor can be found.

    If we are going to create an object with no arguments (using default constructor) but there wasn't any default constructor, then in this step, the compiler had already setup and set aside the memory? I mean I am confused about the order in which this process is taking place. First the compiler sets aside the memory and then after the constructor realized that there wasn't any matching default constructor, then that memory which is already set by the compiler would be released because no matching constructor was found ?

    I also debug the code below, and I realized that creating objects and setting up memory is all about assigning memory for the member variables and the address of the object is the same as the address of the first (in order) member variable of a class. is this finding correct?

    • nascardriver

      The compiler doesn't set aside any memory. It generates the instructions that reserve the memory at run-time. If you can't compile your code (eg. because a constructor is missing), nothing is generated.

      The address of the first member isn't always the same as the address of the object.

  • SAmiRa

    Why can we have 'Date date{}' but can't have 'Date date()' in the code below?

  • default constructor with default parameter

    >> Note that we have given the second parameter of the constructor with parameters a default value

    Note that we have given the second parameter of the constructor with parameters THAT HAVE a default value
    isn't those words missing?

  • ammawn

    "The only difference is that = default allows us the safely initialize member variables even if they don’t have an initializer"

    should be

    "The only difference is that = default allows us to safely initialize member variables even if they don’t have an initializer"

    I think.

    Also thank you so much for these tutorials :)

  • Fang

    > This particular implicit constructor allows us to create a Date object with no arguments, but doesn’t initialize any of the members (because all of the members are fundamental types, and those don’t get initialized upon creation). If Date had members that are class-types themselves, for example std::string, the constructors of those members would be called automatically.

    Cmiiw, but apparently the implicit default constructor will zero-initialize all members as per value-initialization rules (with or without `default` keyword); you should reconfirm this. Also, I found somewhat confusing behavior when we only define class-type variable without initializing it:

    I might be wrong, but it would be helpful if you can double check this. Also thanks so much, I really appreciate you maintaining this in-depth tutorial!

    • nascardriver

      Initialization rules are always a hassle to figure out.

      Default-initialization is performed. `Date` has an implicitly-defined default constructor (Because it has no other constructors), so this constructor is called. The generated default constructor has the same effect as an empty constructor, so `m_day` is default-initialized to to an indeterminate value (ie. it is uninitialized).

      Value-initialization is performed. `Date` has an implicitly-defined default constructor, so is it zero-initialized, which causes all members to be zero-initialized as well (The constructor of `Date` isn't used).

      I updates the sentence you quoted to say the the members don't get initialized unless we use direct initialization (Or list initialization, which is a form of direct initialization).

  • Nguyen


    In the program below, I have char & string.  It works for char, but not for string.
    For string, it only prints out "Hello".  Am I missing anything?

    • nascardriver

      You're using `copy` while defining `copy`, that doesn't work.

      • Nguyen

        You said "You're using `copy` while defining `copy`, that doesn't work."  Is it line 56 you are referring to?  If yes, then why it works for char?  To see if it works successfully for char, please comment out lines 6-8, 16 and 45-48, then remove the comments on lines 10-12, 17 and 51-54.

        • nascardriver

          Yes, line 56. It's the same problem with `char`. You're accessing `copy` before it has been initialized. Accessing uninitialized variables causes undefined behavior.

          • Nguyen

            Sorry if my stubbornness irritates you.  Please bear with me.  I hope it's the same problem with 'char' but it really runs successfully for me.  Have you tried to run yourself?  Please give me a few minutes to have it run on your system.  I use Visual Studio 2017 to run it.  The output looks good to me.

            Here is the output:
            Copy is A, E, and F

            Please copy my below program, paste then run on your system to see if I was right.

            • nascardriver

              Undefined behavior means _anything_ can happen. Anything includes the possibility that the thing happens that you might have expected. If you run it again in 3 years, your PC might explode. That's undefined behavior.

              • Nguyen

                Thanks for your patience.  
                I made it work as shown below:

  • Nguyen


    What's wrong with my program?

    • nascardriver

      What's wrong with your program?

      • Nguyen

        Hi nascardriver,

        Sorry for the earlier program that contained so many errors that I should have corrected before asking.  I modified it, corrected some errors as shown below.  The purpose of my program is to see if the default constructor is called when an object array is instantiated.  

        Although the program produces no errors, it shows nothing on the screen.

        • nascardriver

          Commenting code with errors is no problem, but you should always add the error message to your comment.

          `array` has 2 elements, and you're accessing `array[2]` (The third element). This causes undefined behavior.

          • Nguyen

            Oh, my bad.
            I changed line 34 to array[1].printArray();
            I expect to see
            in the ouput, but I get these following errors

            E0349    no operator "<<" matches these operands    
            C2679    binary '<<': no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)

  • pooyan

    what exactly means for =default to safely initialize member variables ? does it mean initializing each builtin type member variable to 0 if it does'nt have an initializor in class definition?
    and what if a usual constructor gives some other value to a member variable than of initializor in class definition ?
    thanks for great tutorial!

    • nascardriver

      > does it mean initializing each builtin type member variable to 0 if it does'nt have an initializor in class definition
      Yes. An empty constructor won't do this.

      > what if a usual constructor gives some other value to a member variable than of initializor in class definition
      Than that member has the other value

  • Ian

    In quiz 1.b, I wonder why you use initialized by default as below for private member variable instead of using non-initialized or initialized by specific value, on the condition that you have default constructor.

    • nascardriver

      We always initialize everything. If you know what you're doing, you can omit initializations. Until then, it's safer to initialize everything.
      If you don't use the initial value of a variable (ie. you write to it before you read from it), initialize it with empty curly braces. Otherwise the reader may think the value you're initializing the variable with has some meaning. We're initializing for the sole purpose of having well-defined behavior, but don't care about the value.

  • Rohit Alawadhi

    When I do not write the constructor and explicitly delete the copy constructor it fails
    I am assuming that when it creates an object and is getting ready to call the constructor it tries to resolve it with the deleted copy constructor assuming it to be the function, that the user wants to call.
    Why does it not create a constructor itself in this case?
    When I comment out the "= delete" constructor it works fine.

    • nascardriver

      When you delete a constructor, it still counts as user-declared. If there are user-declared constructors, the compiler won't generate a default constructor for you.

  • Gabe

    Quiz 1 a:

    Quiz 1 b:

  • Alexander

    You mentioned at the beginning of this tutorial series that advice would periodically be summed up into three categories: Warning, Best Practice, and Rule. In this chapter, you stated that favoring brace initialization was a rule, rather than best practice, despite the fact that other initialization methods work perfectly fine. Can you explain why you wrote this as a rule rather than best practice?

    • nascardriver

      Brace initialization works almost everywhere, making more code style more uniform. It can also be used to safely initialize variables to default values, no other form of initialization can do this. Additionally, it comes with type deduction, which saves us from typing out type names in return statements or in-line creation of arguments. It cuts a clear line between the visual appearance of initialization and assignment or function call, there's no doubt about what the syntax does. The other initializations can be confusing with operators and function calls.
      Brace initialization is safer by disallowing narrowing conversions, and by not suffering from the most vexing parse (`int i();` is a function declaration).

      You need a very good reason to ignore these benefits and use another form of initialization. One such reason is unintended list initialization when using templates. Topics we'll cover later.

      You're right, it could be a "Best Practice". But a "Best Practice" implies choice, and we don't want readers to choose copy initialization over brace initialization for insubstantial reasons like being used to it from another language.

  • Theo

    Hi, could you help me understanding why it's better to use:

    instead of:

    in Question 1.

  • bissetriz

    This is my solution to quiz 1.a. Is it correct?

    #include <iostream>

    class Ball
        std::string m_color{"black"};
        double m_radius{10.0};
        Ball() = default;

        Ball(std::string_view color)
            m_color = color;

        Ball(double radius)
            m_radius = radius;

        Ball(std::string_view color, double radius)
            m_color = color;
            m_radius = radius;

        void print()
            std::cout << "color: " << m_color << ", radius: " << m_radius << '\n';


    int main()
        Ball def{};

        Ball blue{"blue"};

        Ball twenty{20.0};

        Ball blueTwenty{"blue", 20.0};

        return 0;

      • fnamelname

        not the original poster (bissetriz) of this question, but have a followup question.

        Is there a reason why the tutorial solution does not initialize values for the member variables under "private" like Bissetriz did, allowing us to skip initializing some variables under the different constructors when the user does not supply, but instead opts to have each constructor initialize variables with unsupplied values? Seems like extra lines of code to me.


        • nascardriver

          We don't cover non-static member initialization until lesson 8.5b, so we can't use it here.
          Because we already used it for `struct`, it shouldn't be a problem to introduce it earlier. I'll see what I can do.

  • p1

    So what is the use of constructors against making your own functions?I just see more confusion in naming stuff the same as the class and making my own function which would do constructor things seems pretty easy,and cleaner to read.

  • gbstrcl

    Under Implicit constructors section

    Did you mean the compiler generates a default constructor?

  • MCG

    I think the constructor of the date2 class was misspelled (line 24)

Leave a Comment

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