Search

8.8 — Constructors (Part II)

Private constructors

Occasionally, we do not want users outside of a class to use particular constructors. To enforce this behavior, we can make constructors private. Just like regular private functions, private constructors can only be accessed from within the class. Let’s take a look at an example of this:

One problem with public constructors is that they do not provide any way to control how many of a particular class may be created. If a public constructor exists, it can be used to instantiate as many class objects as the user desires. Often it is useful to restrict users to being able to create only one instance of a particular class. Classes that can only be instantiated once are called singletons. There are many ways to implement singletons, but most of them involve use of a private (or protected) constructor to prevent users from instantiating as many of the class as they want.

Constructor chaining and initialization issues

When you instantiate a new object, the object’s constructor is called implicitly by the C++ compiler. Let’s take a look at two related situations that often cause problems for new programmers:

First, sometimes a class has a constructor which needs to do the same work as another constructor, plus something extra. The process of having one constructor call another constructor is called constructor chaining. Although some languages such as C# support constructor chaining, C++ does not. If you try to chain constructors, it will usually compile, but it will not work right, and you will likely spend a long time trying to figure out why, even with a debugger. 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.

For example, the following:

becomes:

Code duplication is kept to a minimum, and no chained constructor calls are needed.

Second, 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. As mentioned, chaining constructor calls are illegal in C++. You could copy the code from the constructor in your 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!

Note: C++11 now supports chaining constructors via the delegating constructors functionality.

8.9 -- Class code and header files
Index
8.7 -- The hidden “this” pointer

22 comments to 8.8 — Constructors (Part II)

  • Chicken

    Hi all,
    Please propose some ways to implement Singleton class!
    And how to use it?
    Thanks.

  • arikuti

    Hi All ,

    "If you try to chain constructors, it will usually compile, but it will not work right"
    Could you please give me an example for the following statement .. - I tried with below code - I dont see any issuess

    #include
    using namespace std;

    class A {
    public:
    A() {
    cout << "I am in A::A " << endl;
    }
    A(int i) {
    A();
    cout << "I am in A::A(int) " << endl;
    }
    };
    int main ()
    {
    A a(1);
    }

    Out put
    ------
    I am in A::A
    I am in A::A(int)

  • dice3000

    the private constructor part was a bit obscure

  • sanjeev_e

    Hi,

    I got the reason.

    A(10) -> will construct un-named object which was created temporarily and destroyed. By adding the display() function, it was very clear.

    class A{
    public:
    A(){
    x = 0;
    cout<<"Default constructor"<<endl;
    A(10);
    }
    A(int a){
    cout<<"Parameterized constructor"<<endl;
    x = a;
    }
    void display()
    {
    cout<<"x = "<<x<<endl;
    }
    ~A(){
    cout<<"Destructor"<<endl;
    }
    private:
    int x;
    };

    int main(){
    A a;
    a.display();
    return 0;
    }

    Output is now:

    Default constructor
    Parameterized constructor
    Destructor
    x = 0
    Destructor

    Thanks,
    Sanjeev.

  • sanjeev_e

    Can you please explain why the destructor is called twice here?

  • sanjeev_e

    Hi Alex,

    I tried executing the below code snippet with constructor chaining and found the interesting result.

    class A{
    public:
    A(){
    cout<<"Default constructor"<<endl;
    A(10);
    }
    A(int a){
    cout<<"Parameterized constructor"<<endl;
    x = a;
    }
    ~A(){
    cout<<"Destructor"<<endl;
    }
    private:
    int x;
    };

    int main(){
    A a;
    return 0;
    }

    The output is:

    Default constructor
    Parameterized constructor
    Destructor
    Destructor

    The reason is once the control goes out of default constructor the destructor is called here. The destructor will be called only when the object is destroyed automatically/manually(in case of dynamic memory allocation). Can you please explain the reason why it is like that?

    Thanks,
    Sanjeev.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">