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.

Using a separate function

The obvious solution would be to have the Foo(int) constructor call the Foo() constructor to do the A portion. 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 (it turns out, this actually creates a temporary object and then discards it).

However, 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 it’s 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 the 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, std::string). In this way, the amount of redundant code is minimized (we only have to write one constructor body instead of two).

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

38 comments to 8.6 — Overlapping and delegating constructors

  • 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.

  • 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. 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.

      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.

  • 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.

  • 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.

  • 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

  • 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.

  • 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.

  • John Mounir

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

  • 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).

  • 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.

  • 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:

Leave a Comment

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