Search

8.6 — Overlapping and delegating constructors

Constructors with overlapping functionality

When you instantiate a new object, the object’s constructor is called implicitly by the C++ compiler. It’s not uncommon to have a class with multiple constructors that have overlapping functionality. Consider the following class:

This class has two constructors: a default constructor, and a constructor that takes an integer. Because the “code to do A” portion of the constructor is required by both constructors, the code is duplicated in each constructor.

As you’ve (hopefully) learned by now, having duplicate code is something to be avoided as much as possible, so let’s take a look at some ways to address this.

The obvious solution doesn’t work prior to C++11

The obvious solution would be to have the Foo(int) constructor call the Foo() constructor to do the A portion.

or

However, with a pre-C++11 compiler, if you try to have one constructor call another constructor, it will often compile, but it will not work as you expect, and you will likely spend a long time trying to figure out why, even with a debugger.

(Optional explanation: Prior to C++11, calling a constructor explicitly from another constructor creates a temporary object, initializes the temporary object using the constructor, and then discards it, leaving your original object unchanged)

Using a separate function

Constructors are allowed to call non-constructor functions in the class. Just be careful that any members the non-constructor function uses have already been initialized. Although you may be tempted to copy code from the first constructor into the second constructor, having duplicate code makes your class harder to understand and more burdensome to maintain. The best solution to this issue is to create a non-constructor function that does the common initialization, and have both constructors call that function.

Given this, we can change the above class to the following:

In this way, code duplication is kept to a minimum.

Relatedly, you may find yourself in the situation where you want to write a member function to re-initialize a class back to default values. Because you probably already have a constructor that does this, you may be tempted to try to call the constructor from your member function. However, trying to call a constructor directly will generally result in unexpected behavior. Many developers simply copy the code from the constructor in your initialization function, which would work, but lead to duplicate code. The best solution in this case is to move the code from the constructor to your new function, and have the constructor call your function to do the work of initializing the data:

It is fairly common to include an Init() function that initializes member variables to their default values, and then have each constructor call that Init() function before doing its parameter-specific tasks. This minimizes code duplication and allows you to explicitly call Init() from wherever you like.

One small caveat: be careful when using Init() functions and dynamically allocated memory. Because Init() functions can be called by anyone at any time, dynamically allocated memory may or may not have already been allocated when Init() is called. Be careful to handle this situation appropriately -- it can be slightly confusing, since a non-null pointer could be either dynamically allocated memory or an uninitialized pointer!

Delegating constructors in C++11

Starting with C++11, constructors are now allowed to call other constructors. This process is called delegating constructors (or constructor chaining).

To have one constructor call another, simply call the constructor in the member initializer list. This is one case where calling another constructor directly is acceptable. Applied to our example above:

This works exactly as you’d expect. Make sure you’re calling the constructor from the member initializer list, not in the body of the constructor.

Here’s another example of using delegating constructor to reduce redundant code:

This class has 2 constructors, one of which delegates to Employee(int, const std::string &). In this way, the amount of redundant code is minimized (we only have to write one constructor body instead of two).

A few additional notes about delegating constructors. First, a constructor that delegates to another constructor is not allowed to do any member initialization itself. So your constructors can delegate or initialize, but not both.

Second, it’s possible for one constructor to delegate to another constructor, which delegates back to the first constructor. This forms an infinite loop, and will cause your program to run out of stack space and crash. You can avoid this by ensuring all of your constructors resolve to a non-delegating constructor.

8.7 -- Destructors
Index
8.5b -- Non-static member initialization

65 comments to 8.6 — Overlapping and delegating constructors

  • John Halfyard

    Wooohooo… my turn to catch a typo.

    "It is fairly common to include an Init() function that initializes member variables to their default values, and then have each constructor call that Init() function before doing it’s parameter-specific tasks. This minimizes code duplication and allows you to explicitly call Init() from wherever you like."

    "it’s parameter-specific tasks" should be "its parameter-specific tasks"

    P.S.  I’ll be back for the Chapter 8 Comprehensive no doubt.

  • Lamont Peterson

    Alex,

    The first (incomplete) examples at the top of this lesson state that prior to C++11, they won’t work as one might think they should (the point being, use a private function for the common code).  I decided to test it with the C++14 compiler I’m running, so I fleshed out your snippets a little bit and got some interesting (and easily understandable) results.  Here are the two variations of the program and their outputs:

    Variation "A" (1-main.cpp):

    Produced this output:

    Variation "B" (2-main.cpp):

    Produced this output:

    Both programs were compiled on macOS 10.12 with clang++ 8.1.0 using these commands:

    I’m curious to see the results you get from these trying them out on your Windows system(s) (I don’t have a Windows system handy at the moment, just Mac & Linux).  Also, feel free to take these "test" programs and update this lesson with them.

  • AMG

    Hey Alex,
    Example, in addition to calling constructor, another class variable should be initialized. I think it would be important to say that delegated constructor must be called alone, and hence, cannot be combined with other parameters in initializer list.

    • learn36

      I actually wasn’t aware of that until just now. I’ve updated the lesson to note this caveat, as well as a warning about forming infinite delegating constructor loops. Thanks!

  • Christopher Glick

    Alex,
    Maybe I’m being nitpicky, but the example provided here…is passing strings and not by const reference which was just harped on in previous lesson.
    I updated it to what the previous lesson taught us, just sayin!

  • Deepti

    Hi Alex,

    I tried this program below and am unable to understand why this is not working. Also, can you please tell me the difference between this one and the program given in last section(Delegating Constructors)

    My program:
    #include <string>
    #include <iostream>

    class Employee
    {
    private:
        int m_id;
        std::string m_name;
    public:
        Employee(int id = 0, std::string name = "manh") : m_id{ id }, m_name{ name }
        {
            std::cout << "Employee " << m_name << " with id: "<< id << " created.\n";
        }
        Employee(int id) : Employee(id,name)
        {
            std::cout<<"hi";
        }
    };

    int main()
    {
        Employee person{2};
        return 0;
    }

    ***************************************************
    Last section program
    #include <string>
    #include <iostream>

    class Employee
    {
    private:
        int m_id;
        std::string m_name;

    public:
        Employee(int id=0, std::string name=""):
            m_id(id), m_name(name)
        {
            std::cout << "Employee " << m_name << " created.\n";
        }

        // Use a delegating constructors to minimize redundant code
        Employee(std::string name) : Employee(0, name) { }
    };

    • Deepti

      Hi Alex,

      Along with my previous post on delegating constructor, I have few questions.

      1) When and how do I know that I need to use classes to solve problems?
      Say for example when am solving some programs on arrays/strings/pointers/functions etc… - Should I go with traditional programming or use classes?
      To give more precise examples: Find highest element in an array, product of 2 matrices, occurrences of characters in a string….etc..

      2) For learning concepts on Data Structures and Algorithms, what topics in C++ should I be equipped with?

      I know above questions are deviating from current section but would be grateful if you could provide an insight on this.

      • Alex

        1) As a rule of thumb, classes are useful when you need to model both data and algorithms that work on that data. If I had to multiple two matrices, I’d probably create a Matrix class with an overloaded multiplication operator, because I need something to hold both the data and work with it. However, to find the highest element of an array, I’d probably just create a function, because I don’t need to model the data (a standard build-in array would be fine).

        2) Mostly the stuff in chapters 8 through 10 of these tutorials.

        • Deepti

          Thanks Alex for your input.
          One more input I need is on Pointers.
          Am quite weak in this topic, could you please provide me any sites or books that provide programs/exercises on pointers so that i can solve them and get a hang of the same.
          I searched online and only theoretical stuff is what am able to find. Am not able to find any sites that provide required stuff.
          I had a look into the Understanding Pointers in C book by Yeshwant Kanetkar but I dont see any exercises in that as well.
          Need your help here.

          • Alex

            I am not familiar with any other good references on pointers. You’ll have to do your own research on this one. Sorry. Maybe try asking on Stack Overflow?

    • Alex

      This line is wrong. id is being passed in as a parameter, but where is name coming from? The compiler is complaining it doesn’t know what name is.

  • Mr C++

    Please, Give Me An example where one constructor calling another constructor does not what a programmer intended.
    I am asking you to give me an example because i haven’t encountered any problem so far.
    Thanks In Advance 🙂

    • Mr C++

      I have figured out an example for this :-

      The programmer would have intended to print 5 9 on the screen but it prints 5 and a garbage value on the screen !
      And, It not only works for Foo(); but also works even if create an object of type foo(For Eg, Foo Hoo;). I think it is because the changes in m_x and m_y would reflect for Hoo not for Goo.

    • Alex

      You didn’t read the article carefully. In C++11, this limitation was lifted, and constructors can now call other constructors, so long as it’s done in the member initialization list. If you call a constructor from the body of another constructor, it will still not work as you expect.

      • Mr C++

        Man ! Atleast Understand my point !
        I gave an example of one constructor calling another constructor, which results in unexpected results !

  • win

    Hi,Alex
    Could you explain why this code is wrong

    #include <string>
    #include <iostream>

    class Employee
    {
    private:
        int m_id;
        std::string m_name;
    public:
        Employee(int id = 0, std::string name = "") : m_id{ id }, m_name{ name }
        {
            std::cout << "Employee " << m_name << " with id: "<< id << " created.\n";
        }
        Employee(int id) : Employee(id, "manh"){}
    };

    int main()
    {
        Employee person{199};
    }

    • Alex

      The compiler can’t tell whether you’re intending to call Employee(int) or Employee(int, std::string) with std::string being a defaulted parameter.

      You should get rid of the second constructor and make “manh” the default value for the std::string in the first constructor. Then the ambiguity will be resolved.

  • Daniel

    Hi Alex,

    In the program below, I get an error of "call to overloaded function is ambiguous" when I use the first delegated constructor.

    Why is that? How can I overcome this issue?

    • Alex

      Your problem is that you have two default constructors:

      Either make the latter one not a default constructor (don’t put a defaulted value on parameter received), or get rid of the constructor with no parameters and just use the one with all default parameters.

  • Ehsan

    Couldn’t we have benefited from default arguments in the second example to minimize the code even further (and possibly with performance gains)?

    Consider:

  • Rob G.

    Great chptr Alex!

    One question (remedial): when making a variable non-const, removal of the const keyword I understand. But also the reference operator & as well? Code would only work if oth removed.

  • Philip

    Make sure you’re calling the constructor from the member initializer list, not in the body of the constructor.

    Why shouldn’t I call the constructor from a different constructor? And in this case?

    How should this be converted to code that uses the member initialization list instead of a function call?

    Appreciate the help in advance,

    PS. With a c++ 11 compliant compiler calling a different constructor did not give me any trouble so far.

    • Philip

      Converted into code without having to add another function*

    • Alex

      Consider what happens if you call foo(a, b) from the body of a normal function. It constructs an anonymous (unnamed) foo object (we talk about anonymous objects later in this chapter), and then discards it after the expression is evaluated.

      The same thing happens when you call a constructor from the body of another constructor. C++ thinks you’re trying to construct a new anonymous object, so it calls the constructor you want, but on a new object, not the same object that you’re already initializing. This is legal syntactically, but probably not what you intended.

      There’s no way to use delegating constructors in the case above, since a and b are apparently somehow derived from the body of your default constructor. You’ll have to find some other initialization pattern that works (e.g. simple assignment).

  • John Mounir

    so when a constructor calls init() it actually assign values to class member variables not initializing it, am i right ?

  • Mekacher Anis

    Hi I wanna ask , I came this far but I still don’t understand what is the relation between the namespace std and the header files that we include and what they contain .
    and thanks from the buttom of my heart

    • Alex

      Header files contain all of the declarations required to use some set of functionality (functions, classes, types, etc…) in another file. For example, if you want to use strings, you include <string>.

      Namespaces exist to help reduce naming conflicts between different sets of functionality. All headers belonging to the C++ standard library put their functionality inside namespace std, as a way to ensure that the names they use don’t conflict with names that you use in your own programs.

      • Mekacher Anis

        so if I’m right the header files contain the forward declarations of functions , etc and the implementation it self is in the namespace std
        and the namespace std and header files are completely separate from each other
        and thank’s because u enlighten me every single day

        • Alex

          Not quite right.

          The header files contain the forward declarations, which may be in a namespace.
          The implementation is in the code (.cpp) files, which may also be in a namespace.

          The header files allow you to selectively use functionality you want.
          The namespace helps ensure the names of things in the header files don’t conflict with the names of things in your programs.

          • Mekacher Anis

            Really sorry for asking again , but now I understand that my problem is "Not understanding what is a namespace even with reading your lesson on namespaces "
            so what is it ?
            and what do u mean with “maybe in a namespace ” ?Do u mean the .h file it self is in the namespace or the namespace contain only using “.h” ?
            forgive my brain is like a turtle understands slowly
            and thank’s for making this wonderful community

            • Alex

              Let’s try an analogy.

              Putting an object (e.g. a variable or class) inside a namespace means that we need to access that object by using both the namespace name and the object’s name. That’s all namespaces really are -- an added level of naming. They’re kind of like last names in real life. My name is Alex. As long as I’m the only Alex, you can call me Alex. But as soon as I’m put in a group with another Alex, the name “Alex” becomes ambiguous. This can be resolved by calling me by both my first name and last name. My last name acts kind of like a namespace in this regard -- it helps disambiguate who I am, and unless someone else happens to have both the same first name AND the same last name, it avoids naming conflicts.

              Namespaces can be defined anywhere: inside .h files, or inside .cpp files. A single namespace can appear in multiple .h or .cpp files. For example, the iostream header defines std::cout, whereas the string header defines std::string -- both are in namespace std. Kind of like how both me and my sister have the same last name, but live in different houses.

              By “maybe in a namespace”, I mean putting the code you write inside a namespace is optional. You can if you want to.

          • Mekacher Anis

            thank’s for the amazing analogy every thing is crystal clear now thank’s , I really can’t express how grateful and thankful I’m right now you made my day

          • Paul

            So, basically, we should implement a namespace whenever we anticipate a potential naming conflict?

            • Mekacher Anis

              I think so , or maybe when u want to look smart and cool programmer 😉

            • Alex

              You can do so either proactively (e.g. if you’re writing a reusable library that may conflict with another library), or reactively (if you find one of your names unexpectedly conflicts with something else). Personally, I usually take the reactive approach.

  • Steiner

    Hello Alex,

    There seems to be an compilation error when I tried to copy and compile the code found in the last section (Delegating constructors in C++11). The error can be found on this code:

    This is the only one that gives the compilation error:
    error: expected ‘)’ before ‘name’.

    When I commented this one out, the code works as expected.
    NOTE: compiled using g++ (GCC) 5.3.0 with -std=c++11 flag

    Thank you very much for the tutorials.

    • Alex

      I forgot the std::prefix on string. Perhaps this is confusing your compiler? Try changing string to std::string and see if it works.

      • Steiner

        Hello Alex,

        adding in the std::prefix on string has solved the problem :). I usually add in using namespace std at the very beginning of the code and this one slip up took me too long to figure it out. I thought I was having syntax errors since delegating constructors is a new thing for me.

        Thank you for your reply.

  • Herrick

    Hi Alex,

    Really enjoying your tutorials - I’m a teacher (music) and wish I could explain things as clearly as you!

    Anyway just a quick question on the last section of code - Why have all three constructors got the word ‘public’ at the start of each line? I thought it only needed to be defined when switching from the current access specifier.

    Thanks in advance,
    Herrick

  • Alex

    Thanks for the lesson!
    Some html formatting is missing from the last code block.

      • Darren

        Are you taking to yourself from the future? Check out the date-time stamps; this messes with causality- weird!! (Unless its a timezone thing)

        • Darren

          Oh snap! It’s a 12 hour clock!! 12:49 am is 00:49 hrs i.e. about ten to one in the morning. Causality restored; no time paradox here!

          On another note I’m getting a lot of "Gateway Timeout Errors" and "Internal Server Errors" when I try to post a comment. Might this be something to do with traffic to the site being too much for the servers bandwidth? From these error messages I’ve seen that you’re using WordPress to host this site, and WordPress uses nginx as it’s server engine. That implies the server is on Linux machine and uses fastcgi_pass to handle php requests(?) If so check out the nginx configuration file(s) if you can, my suspicion is a dodgy setting in either the "Timeouts" section and/or the "Buffers" section but might be completely wrong. I mean it might be that the Linux machine has gone a bit squiffy / or the hardware (firmware) needs upgrading.

          • Alex

            Yes, I get those errors too sometimes, and the site is sometimes less responsive than it should be. I’ve been unable to locate the root cause, though I have a few potential leads. I’ll keep looking into it.

        • Darren

          I did not know about constructor delegation within a class; very handy. - every day is a school day.

  • Pofke1

    Hi Alex!
    Is it possible to reinitialize class object? If i use one constructor to some objects with the same variables and i want to call another constructor on few of them (already initialized) to set them other variables what should i  do? Im using vector <class> objectName, maybe theres way to call one constructor for objectName[1] - objectName[5] and another for objectName[5]-objectName[10] etc. ?

    • Alex

      No, there’s no way to reinitialize an object once it’s been created. But you can assign a new value to it, assuming the object supports that.

      So you could create your array, and then use a loop to assign values to the different elements in different ways.

  • bantoo011

    why constructors have not any return type . please explain me

    • Alex

      When you create an object of a class type, the appropriate constructor is called automatically by the code that creates the object. Because you can never call a constructor directly (in a context where the return type matters), there’s no need to specify a return type.

      In short: You don’t need to specify a return type for a constructor because there’s never a context in which doing so would matter.

      (Comment edited to avoid confusion)

      • AS

        From comments "if the code that creates the object needs a return type, it can add that to your constructor. If it doesn’t, it doesn’t need to".

        Does that mean a constructor can return a value?
        I tried, but it doesn’t compile in C++11 with CodeBlocks 13.

  • Tom

    “be careful when using Init() functions and dynamically allocated memory. Because Init() functions can be called by anyone at any time, dynamically allocated memory may or may not have already been allocated when Init() is called. Be careful to handle this situation appropriately — it can be slightly confusing, since a non-null pointer could be either dynamically allocated memory or an uninitialized pointer!”

    Alex -

    So what’s the correct way to handle the situation? Is it as simple as making sure to set the dynamic memory pointer to NULL (or to a valid address) before the Init() functions can be called?

    Thanks!

    • First, make sure the constructor sets the pointer to NULL if it’s not going to allocate memory to the pointer. Failure to do so will cause a problem somewhere along the line.

      Second, before allocating memory in Init(), check to see if the pointer is non-NULL. If it’s non-NULL, then Init() has probably already been called, and no allocation is needed. If it’s NULL, then Init() can do the allocation.

      • mslade

        Another solution would be a state flag indicating whether or not the class has been initialized.

Leave a Comment

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