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)

  • bantoo011

    why constructors have not any return type . please explain me

  • Code Geek

    The examples in this chapter don't explain well. I don't really understand the significance of using a private constructor.

  • Moogie

    Oh no! This is the first disappointing chapter in the series, as it doesn't really make any attempt to explain why or how you would use a private constructor. What a combo-breaker!

    We're taught that constructors happen automatically when a class is instantiated, so why have "Book()" at all if it makes "Book cMyBook;" invalid? And how exactly does this stop multiple classes being created, as hinted to in the short paragraph following the example code??

  • dribbit

    I don't understand how a private constructor is used since you can't call it from main... and is calling a single constructor explicitly from the object itself (e.g. object.ConstructorFunction() ) valid?

  • Swapna

    I really found your notes very interesting and i learnt many things from it. Thanks alot. But i had a query to pose, please do take time to answer it as its very important for me to know.

    Question: I created a private default constructor in "Class A". Now i derived "Class B" from "Class A". How can i create an instance for "Class B"?

    Program:

    class A
    {
    private:
    A() {};
    };

    class B
    {
    };

    int main()
    {
    B b; //(or) A *pb = new B(); (or) B *pb = new B();
    return 0;
    }

    Result: error C2248: 'A::A' : cannot access private member declared in class 'A'

    I know that when we create an instance for child class it calls the parent class default constructor first but as the parent class default constructor is private, we cant create it.

    But Can you please let me, what is the need of private deafult constructors and how can we create an instance?

    Thanks
    Swapna

    • Biraj Borah

      hey i guess its too late to answer to your question but still

      Private constructor helps to make sigle instance of a class ...This is called SINGLETON PATTERN ....Consider a real world example where you have an institute in which there can be only one HEAD for that institute .So this HEAD should be singleton ....

      Now the question is how can we instanciate an object of such class ..

      For that we need to make use of static methods .As we know that a static method/function can be called by the class name (So there is no need to instanciate the class to call the method )

      have a look at the code below

      class Head
      {
      private:
      static bool instanceFlag;
      static Head *instance; // a pointer of type Head

      Head()
      {
      //private constructor
      }
      public:
      static Head* getInstance();

      ~Head()
      {
      instanceFlag = false;
      }
      };

      bool Head::instanceFlag = false;
      Head* Head::instance= NULL;
      Head* Head::getInstance()
      {
      if(! instanceFlag) // checks if the instance is created already
      {
      instance = new Head();
      instanceFlag = true;
      return instance ;
      }
      else
      {
      return instance ;
      }
      }

      int main()
      {
      Head *sc1 ; // rem this is not instaciating an object we are
      //just creating a pointer of type Head
      sc1 = Head::getInstance(); // calling a static method
      return 0;
      }

      So by the above u can get it ... also in place of using the instanceFlag u could have gone ahead and checked the pointer
      if(instane == null)
      {
      instance = new Head() ;
      return instance ;
      }

      thanks

      Biraj Borah
      Cdac- WIMC
      Pune

  • baldo

    I noticed a small typing error. Some weird characters appear in the line: "the object’s constructor".

  • cammy

    Is there something wonky with the navigation button that takes you to the previous lesson? It appears to me as 'The hidden “this” pointer' rather than 'The hidden 'This' Pointer' as the lesson is titled.

    • Fixed. Looks like all the " got turned into ”. I've seen this happen a few times before. I'm not sure if it's a general wordpress database corruption issue or a result of something trying to use an injection SQL attack or something.

  • cymkhat

    You dont need a private constructor (i.e a private constructor is NOT A MUST) to restrict an object being instantiated without arguments.

    --If you want a object to be instantiated in a particular way (with the constructor which has arguments) : just declare/define an constructor that takes arguments and intializes the object in that particular way.

    --YOU DO NOT NEED A PRIVATE CONSTRUCTOR FOR THAT

    --look at the following code and try to compile it. it will give the following error. see that I did not declare a private constructor yet the compiler fails to compile as there exists a constructor with arguments.

    
    #include 
    #include 
    #include 
    using namespace std;
    
    enum CarSize{
            small = 0, medium = 1, large = 2
    };
    
    class RentalAccount{
            string accountNumber;
            string clientName;
            int age;
            float balance;
    
            public:
            // -- Constructor
            RentalAccount( const char* newAccountNumber,  const char* newClientName, const int newAge, const float newBalance = 0) { }
    
            // -- Set, and get Balance
            void SetBalance(const float newBalance);
    
            float GetBalance() const;
    
            // -- Calculate Balance
            void CalculateBalance(CarSize carSize);
    
            // -- Print Client information
            void Print() const;
    };
    
    
    int main()
    {
            RentalAccount *C = new RentalAccount();
    
            return 1;
    }
    
    

    when you compile this - you will get the follwing error. Anyway the compiler is returning an error even though you I didn't declare a private constructor, so I dont think a private constructor is needed to prevent somebody from instantiating an object using a plain constructor without any arguments. just declare a constructor with arguments and the compiler will do the rest.

    cymkhat@cymkhat-laptop:~/cpp$ g++ cons.cpp
    cons.cpp: In function ‘int main()’:
    cons.cpp:35: error: no matching function for call to ‘RentalAccount::RentalAccount()’
    cons.cpp:18: note: candidates are: RentalAccount::RentalAccount(const char*, const char*, int, float)
    cons.cpp:10: note: RentalAccount::RentalAccount(const RentalAccount&)

    my g++ version is

    cymkhat@cymkhat-laptop:~/cpp$ g++ -v
    Using built-in specs.
    Target: i486-linux-gnu
    Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
    Thread model: posix
    gcc version 4.2.3 (Ubuntu 4.2.3-2ubuntu7)

    • I have rewritten that portion of the lesson to reflect a more appropriate usage for private constructors. Thanks for letting me know I made a mistake with this.

    • abcd

      I noticed that you have a wrong creation of object. You have used

       RentalAccount *C = new RentalAccount();

      where as in your constructor, you need to have some values because of the
      parameters:

      const char* newAccountNumber,  const char* newClientName, const int newAge,

      Replace the above with this and the code should compile:

      const char* newAccountNumber=" ",  const char* newClientName=" ", const int newAge=0,
  • 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 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="">