Search

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.

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:

0/1

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.

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:

A
B

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
Index
8.4 -- Access functions and encapsulation

216 comments to 8.5 — Constructors

  • stuart

    why is (const std::string &colour) preferred as a parameter in ball constructors over (string color). I used latter and the results were same. is it more efficient?

    • Alex

      string color means the argument will be copied into the parameter. const std::string &color means color will be a reference to the argument, which avoids making a copy of the std::string. Simply put, using a reference is more efficient.

  • Luhan

    I don’t know if you already talked about this, but there is a specific reason to use only const with string, and not with the double?

    • Alex

      We use const with the string because the parameter is a reference parameter, and:
      1) We don’t want to accidentally modify the argument passed in
      2) Using a const reference lets us pass in string literals and r-values, whereas using a non-const reference does not

      The double parameter, not being a reference, doesn’t have either of these issues. We definitely could make it constant, to show that the function isn’t going to modify it, but it’s a copy of the argument anyway so the incremental value provided by doing so is low.

  • Bari

    Hi Alex!
    In your solution to quiz question 1b in which you only use 2 parameters, you gave default values to the 2nd constructor but you didn’t give those in the Constructor with only radius parameter. Why?
    And when I try to give a default value to this radius parameter

    It gives an error to the line 33 of the solution code. Why is that?

    • Alex

      A class can only have one default constructor. If I’d given default parameters to the one-parameter constructor, then the class would have two default constructors, which would result in ambiguity when constructing objects using the default constructor. Presumably that’s the error you’re getting.

  • Finn St John

    Hi Alex,

    In your quiz solutions you pass in strings by reference. Are they really large enough to warrant passing by reference rather than passing by value?

  • Nima

    Hi dear Alex.
    Why if I run this code constructor and destructor are called only one time?
    I expect that constructor and destructor should be called twice not once.
    I’m really confuse.
    Thanks in advance.

    • Alex

      The compiler is eliding the return value of pointcreator() for efficiency. I discuss this in lesson 9.11.

      • Nima

        Thank you so much.
        I read lesson 9.11 but my question still persists.
        how compiler knows how to initialize p1 without calling constructor or copy constructor for p1?
        in lesson 9.11 you tell that compiler see:
        Fraction fiveThirds(Fraction(5, 3));
        As:
        Fraction fiveThirds(5, 3);
        Ok, I got it.
        But sounds really strange p2 initialize in pointcreator function and destruct at the end of the main function!
        Can you help me a bit more?
        Thank you so much.

        • Alex

          It may sound strange, but that’s what’s happening for efficiency. The compiler has rules about when it’s allowed to elide the copy constructor. This is one of those cases. If you compile in debug mode, you’ll see what it’s doing without the optimizations.

  • AMG

    Hey Alex,
    "Generally speaking, it’s a good idea to always provide at least one constructor in your class. This will prevent C++ from creating an empty default constructor, ensuring that users don’t instantiate objects of your class that have uninitialized members (unless you intend for that to happen).
    Rule: Provide at least one constructor for your class, even if it’s an empty default constructor."
    Trying to understand the difference between C++ empty default constructor and mine. Either empty constructor generates garbage, so why mine is better? I thought the idea to provide non-empty default constructor to prevent accidental generating class object.
    About using class constructor to reset class.

    I believe classes a and b will be destroyed outside { }, and hence, constructors can be used to re-initialize (reset) classes a and b. Thank you very much for your time.

    • Alex

      Yours is better for two reasons:
      1) It’s better to be explicit about your intentions than implicit
      2) When you define your first non-default constructor (including copy constructors or move constructors), the compiler will no longer generate a default constructor for you, meaning your program will no longer compile if it was relying on this constructor existing.

      I’ve updated the lesson slightly to make this more clear.

      If you want to prevent accidental generation of a class object, it’s better to explicily delete the default constructor (we cover how to do this in a later lesson).

      Constructors don’t “reset” classes, they simply create (and optionally initialize) them.

  • codenoob

    I misunderstood the question a bit and (yet again) did things a bit differently and now (yet again) I’m here asking questions. 😀

    Here’s my code:

    This seemed to work and the question that remains is: is this wrong or a worse way compared to your example?

    It’s funny how I struggle and struggle to make a program work and when I get it to work I think I’ve nailed it. Then most of the time when I open your example, I see I’ve done things in a very different way and am left wondering if it’s good or not.

    I’m curious about that if I get a program working (or it at least seems to work) when or how will I learn to recognize what is good coding and what is not?

    • Alex

      It’s a little more redundant than the answer I wrote, but it’s not “wrong”. Often I’ll write my first pass at a solution in a less than optimal way, and then go back and fix it up. So I think the main difference is just the ability to see where things can be optimized. That will come with time and experience.

  • Pavol

    Hi Alex, I have troubles when I try to use a constructor list with three different types, namely:
    Nuclide(std::string name, char state, double halfLife);

    My default constructor looks like this:
    Nuclide::Nuclide(std::string name = " ", char state = ‘A’, double halfLife = 1.E+99):  // Default constructor
                    m_name{name}, m_state{state}, m_halfLife{halfLife}
    {…}

    When I try in main.cpp:
    Nuclide Am241("Am-241", ‘A’);

    I get a compiler error "no matching function for call to ‘Nuclide::Nuclide(const char [7], char)’. Is this because the three types are different? If yes, should I write a default constructor for each combination of parameters?

    pavol.thanks();

    • Alex

      This compiles fine for me in Visual Studio 2017. I tried this:

  • Hamed O.Khaled

    Hi Alex!
    There is something weird that I couldn’t find an explanation! when running this code it runs ! how!! should it give me error because now we have 2 constructors that ready to accept 0-arguments ? or in other words why he calls his default constructor ?

    • Alex

      I’m surprised this compiles too. Here’s what’s happening. The compiler is treating “A a()” as the forward declaration for a function named a() that returns an object of type A by value. Because of this, it’s never actually constructing an object of type A. So even though you haven’t two default constructors, the compiler isn’t complaining because there’s no ambiguity (neither are ever needed).

      If you change “A a();” to “A a;”, you’ll get the ambiguous call error that you’re expecting.

  • The Perplexed Programmer

    Hello Alex!
    Help me out! The following snippet does not work! The screen is blank, that’s all!

    Wait a second…
    Could it be because the class names don’t start with a capital letter?
    Well, help me!

  • :|

    Hi, in the first quiz question i tried to use default parameters, but i dont understand why the code doesnt work:

    • Alex

      You put your default parameters on the print function. They should be on the constructor.

      Right now this line is causing problems:

      The compiler doesn’t know how to create a Ball with a parameter, because your Ball class has no constructors (except the automatically provided default one).

  • lovepreet

    hey alex i want to know how to create this program…………..2.Write a class called Circle which has two constructors. One takes three doubles in its constructor corresponding to the X and Y coordinates and the radius. The other default constructor supplies default values for the coordinates and radius. Please round computer results to 2 decimal places when displaying results. The class must include these methods:
    a)public double circumference() – returning the circumference
    b)public double area() – returning the area c)public void setRadius(double r) – is called in the constructor and checks the radius against a maximum. If the radius is greater than the maximum, setRadius resets it to the maximum (using the ternary conditional operator)
    d)public void printAttributes() – prints the coordinates, the radius, the circumference and the area.
    e)public boolean isInside(int x, int y) – tests whether or not a point falls inside the circle
    f)boundingBox(); – prints the coordinates for the box that contains the circle
    g)move(x, y) – moves the origin by a specified amount

  • Omri

    When a class say n_class is present with a constructor of which all its parameters x,y,z have defalt values it turns out that, as expected:
    n_class b(x);
    n_class d(x,y);
    n_clasd e(x,y,z);
    compile and b,d,e "behave".
    Following this pattern of argument elimination, it is tempting to create a default n_class object c as follows:
    n_class c();  
    This compiles but c does not "behave".
    Variable c is not recognized as an n_class object and an attempt to use it as such leads to an error.
    Thus a default n_class object is created (not strictly following the pattern of argument elimination) as follows:
    n_class c;
    Is this observation correct?
    On the other hand, creating a default anomynous object of type n_class and launching a member function, say print() using it is done as follows:
    n_class().print();
    Quite confusing…

    • Alex

      Yeah, it’s confusing. C++ tends to overload a lot of symbols for different purposes, and this means statements that look similar may have different interpretations by the compiler. The statements for instantiation of a class variable and forward declaration of a function end up looking really similar:

      In the above case, the compiler differentiates the two based on whether the argument is a type or a value. But then consider this:

      With no type or value, should the compiler interpret this as an instantiation of variable x or a forward declaration for function x?

      The way the C++ designers resolved this was as follows:

  • omri

    Hello Alex,
    Thank you for the reply.
    To me this means that Fraction(6) from above is indeed not an explicit call to Fraction(…) but rather a syntax to create an anonimous Fraction(…) object, use it in the statement, afterwhich it is perhaps immediately deleted by the system.
    Since Fraction(…) does not return anything (as it is a constructor), this makes sense to me.
    Did I get it right?
    If yes, perhaps this syntax should be mentioned in the article and it not being a function call (despite the similarity) pointed at. Just a thought…

    • Alex

      Yes, you have it right. I talk more about anonymous objects later in this chapter.

      I thought about mentioning the fact that it’s not a function call, but it’s more of an interesting bit of trivia than anything actually useful. 🙂

  • Omri

    Regarding from above:
    "B contains A as a member variable",
    is it not more accurate to say:
    "B contains a type A as a member variable"
    or
    "B contains a class A as a member variable"?

  • Omri

    Hello Alex,
    Regarding from above:
    "Note that constructors are only used for initialization. They can not be explicitly called."
    As I understand you did explicitly call the constructor when you copy initialized above, and also, in examples given in a later blog you did call the constructor explicitly to create what I think is an anonimous object as you needed it. Please correct me.

    • Alex

      A few things here:
      * First, constructors actually can be called explicitly, but there’s rarely a case where you’d actually want to do so.
      * Second, when we do copy initialization, we’re not actually calling the constructor directly (even though it looks like it). We’re actually telling the compiler to create the object, and that has the biproduct of calling the constructor once the memory has been set up.

      I’ve updated the article to clarify what I was trying to get at: “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).”

  • Alexander Kindel

    What is the difference between setting default values for class members using a default constructor and setting default values when one declares the members? In other words, is there a difference between

    and

    ?

    • Alex

      In the former case, those values will be assigned to all objects created using that specific Ball() default constructor.
      In the latter case, those values will be assigned to all objects created using any constructor, unless the specific constructor used to create the Ball overrides those defaults.

      In your specific case, because you only have one constructor, and it initializes the members to the same values in both cases, this is essentially identical (outside of the fact that the latter case does an initialization, and the former case does an assignment)

  • mandy

    for the Fraction class, how can you get the user to input mixed fraction as default? for example: instead of adding 1/2 + 2 1/2 they’ll have to input as 0 1/2 + 2 1/2
    I got my fraction class to work down to reduce result but I can’t get the mixed number input to work only straight fraction. Please advise.
    oh btw, thanks for creating this site. I use it instead of my cs school book:)

    • Alex

      I’ve read your comment three times and I’m still not sure what you’re asking. Can you clarify?

      If you’re asking how to enter a value like 2 1/2, you could do it as a constructor that takes three numbers: a whole value, a numerator, and a denominator. You can reduce the numerator and denominator and leave the whole value alone.

  • Cassey

    Hi i am a beginner and have problem to understand the default construct. I was given a simple question but i can’t solve it. Please help me

    Implement a default constructor for the following class:

    class Student
    {
    private:
    int StuMatricNum;
    string StuName;
    double StuGPA;

    public:
    Student ( );
    viod DisplayCollegeProfile( );
    };

    //i look through many tutorial but still confused with constructor.

  • Dekasi

    Hi, Alex. I want to ask you why you say that we need to provide at least one constructor even if it is empty default constructor. Is it different from the one that C++ will provide for us (if we don’t provide any)?

    I noticed that you use a reference string variable in the 1st solution of the quiz. Why you use it as a refernce instead of normal string variable?

    • Alex

      As the lesson says, if you don’t provide at least one constructor, the compiler will provide an empty default constructor for you. This is almost never desired, as it means your member variables may not be getting initialized properly.

      You should always pass class objects by (const) reference to avoid making an unnecessary copy.

  • Rohit

    In the topic classes within classes when b is constructed B() will b called which contains only printing statement, then how will it call class A constructor because m_a is not initialized in B() constructor?

    • Alex

      Member variables that are classes (e.g. m_a) that are not explicitly initialized are initialized using the default constructor. So m_a is initialized using the default constructor for class A.

      • Rohit

        My question is in this piece of code :
        B() { std::cout << "B\n"; }
        when b object is declared B() constructor will be called and only the printing statement which says "B" must print because B() constructor is not accessing the the m_a variable in its statements. According to me the output should be "B".
        Please clear my doubt if I am wrong somewhere

        • Alex

          When a class object (such as b) is created, all members of that class are also created. The constructor gives you the opportunity to initialize these members. For class members, if you do not explicitly initialize them, they will be initialized using the default constructor. That’s what’s happening here. The B() constructor is not initializing m_a. However, m_a still needs to be created as part of the B object. So it uses the A default constructor to do so.

  • Rafael Rossi

    What is the difference between:

    and

    • Alex

      With the ampersand, color is a reference to the original std::string argument passed in. No copy is made.

      Without the ampersand, the argument passed in passed by value, causing the argument to be copied into parameter color. This means we can change color without changing the original argument, but at the cost of making a copy.

      In almost all cases, passing a class by const reference is better.

  • vaseem

    rather than any constructor

  • vaseem

    why default constructor has not any return type?

    • Alex

      Constructors are never called directly by the end user. They are called implicitly when an object is created, and the return value of object creation is the object itself.

      The language designers through it was clearer to omit any return type for constructors (and destructors) as a way to denote them as “special” functions.

  • Martin

    Thank you for these great tutorials! They are the best I know so far.

    Just wanted to let you know that there is a wrong indentation for the default constructor in quiz 1 and the comments.

  • simberdavid

    hey why won’t this work?

    • Alex

      It doesn’t work because it has a few problems:
      1) You spelled denominator wrong inside the constructor.
      2) You forgot to include the () for the function calls inside function main().

      Fix those and it will run, though it’s not a great idea to do input in a constructor (it’s better to do the input outside of the class, then pass the values to the constructor).

  • Luzaritz

    Hi Alex

    May I suggest you include in the lesson the way C++ handles defaulting parameters when calling a constructor? Without knowledge of the rule, new learners cannot really answer the 1b quiz. And what about

    in 1b, which would provide a (first) default constructor, according to "has parameters that all have default values". Here, what is legal, and could be reasonably added to the lesson?
    Regards

    • Alex

      Default parameters for constructors are handled in the exact same way as default values for any function. I’ve added a note to the lesson since this was implied rather than stated.

      A class can only have one default constructor, so if you gave radius a default value as per your suggestion, the compiler would error on the second constructor since both constructors would be defined as default constructors.

  • Zachary Fojtasek

    for 1b, why can I not use just this?:

    • Alex

      Because std::string is a class, and you should pass classes by const reference instead of by value, so they aren’t copied.

      • Zachary Fojtasek

        What I mean is, the code won’t compile if I use that as my only Constructor.

        • Alex

          Yes, the way default parameters work is that you can only default the rightmost parameters, and when you supply your arguments, you can’t skip any of the leftmost arguments.

          In the case of Ball twenty(20.0), you’ve skipped providing an argument for the color.

          • Nurlan

            One more question about default parameters. Why we can’t use uniform initialization for default parameters in case it is used as constructor default parameters or as function default parameters?
            In either cases uniform initialization doesn’t work, the default parameter only accepts copy initialization even it is C++11 compatible.

            For  example:
            class Date
            {
            private:
                int m_year;
                int m_month;
                int m_day;

            public:                                    
            //int day=22 accepts,                                                                                                       
                Date(int year, int month, int day{22}) //not int day{22}
                {
                    m_year = year;
                    m_month = month;
                    m_day = day;
                }

                // No default constructor provided
            };

            int main()
            {
              
                   Date today(2020, 10, 14); // today is initialized to Oct 14th, 2020

                return 0;
            }
            Thanks in advance!

            • Alex

              I’m actually not sure why default parameters are required to use the copy initialization syntax. I did a quick search and wasn’t able to dig up anything on the subject either. So for now, this remains a mystery. 🙂

      • Zachary Fojtasek

        UPDATE: I figured it out, it has to do with the rules for default parameters, but now I am confused about something else:

  • Sam

    Hi!
    Just tried something out:
    If create an implicit default constructor (by compiler) and create an instance like so:

    Then there’s a warning that the "thing" is unreferenced and its members contain garbage values.
    But if create an instance like so:

    Then the warning goes away and all members are initialized in type-dependent zero-state (like if you initialize any type with empty brackets of uniform initialization). The same result happens if you create an explicit default constructor like so:

    And in this case, it doesn’t matter how you create an instance (1st or 2nd variant I provided).
    A bit confusing!
    p.s. just run it in MVS 2015

    • Alex

      This only works if you don’t define _any_ constructors yourself (which is something you shouldn’t do), because then the class is treated like a plain-old-data struct, and can be initialized thusly. This violates encapsulation principles.

  • Zachary Fojtasek

    Can a class contain an object of the same class as a member variable? Or perhaps an array containing other objects of the same class?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter