Constructors for Initialization

  1. A special member function of a class, called a constructor, is often introduced to initialize the values of some or all member variables at the time when they are declared.

  2. A constructor must have the same name as the class.

  3. A constructor's function definition cannot return a value.

  4. No type, not even void, can be given at the start of the constructor's function prototype or in the function header.

  5. A constructor is automatically called when an object of that class is declared.

  6. A constructor is placed in the public section of the class definition.

  7. A constructor for the BankAccount class is shown below:

    class BankAccount
    {
    public:
       BankAccount(int dollars, int cents, double rate);
       //A constructor to initialize the account balance to $dollars.cents and
       //initializes the the interest rate to rate percent.

       void set(int dollars, int cents, double rate);
       void set(int dollars, double rate);
       void update( );

       double get_balance( );
       double get_rate( );
       void output(ostream& outs);

    private:
       double balance;
       double interest_rate;
       double fraction(double percent);
    };

  8. The function definition of a constructor is given in the same way as any other member functions, except no return statement and no type can be given. One way to define a constructor for the BankAccount class is as follows:

    BankAccount::BankAccount(int dollars, int cents, double rate)
    {
       balance = dollars + 0.01 * cents;
       interest_rate = rate;
    }

  9. Now two objects of type BankAccount can be declared and initialized as follows:

    BankAccount account1(10, 50, 2.0), account2(500, 0, 4.5);

    As a result, account1 is declared and account1.balance is initialized to 10.50 and account1.interest_rate is initialized to 2.0. Similarly account2 is declared and account2.balance is initialized to 500.00 and account2.interest_rate is initialized to 4.5.

  10. A constructor name is often overloaded so that objects can be initialized in more than one way. You overload a constructor name exactly the same as you overload any other functions.

  11. When a constructor has no arguments, do not include the parentheses in the object declaration. However, parentheses are required if the constructor is called explicitly in an assignment statement.

  12. Calling a constructor creates an anonymous object with new values. An anonymous object is an object that is not named as yet by any variable. The anonymous object can be assigned to the named object. For example, the following call to the constructor BankAccount creates an anonymous object with a balance of $999.99 and interest rate of 5.5%. This anonymous object is assigned to object account so that it too represents an account with a balance of $999.99 and an interest rate of 5.5%:

    account1 = BankAccount(999, 99, 5.5);

  13. If a class has no constructor, then the compiler will actually generate a default constructor that does nothing. This default constructor will be called if class objects are declared.

  14. On the other hand, if the class has at least one constructor, then the compiler will generate no other constructors.

  15. THe following example illustrates a potential problem associated with constructors:

    class SampleClass
    {
    public:
       SampleClass(int Parameter1, double Parameter2);
       void do_stuff( );
    Private:
       int data1;
       double data2;
    };

    This is a legal way to declare and initialize an object of type SampleClass:

    SampleClass my_object(7, 7.77);

    However the following declaration is illegal:

    SampleClass your_object;

    because the class SampleClass has a constructor so no default constructor is generated. The compiler interprets the line as declaration of the object your_object using a constructor with no arguments. But there is no definition of such a constructor.

  16. In order to declare an object without initializing the values of its member variables, a constructor with no arguments must be introduced. Such a constructor is called a default constructor.

  17. For example, the above class SampleClass can be redefined as follows:

    class SampleClass
    {
    public:
       SampleClass(int Parameter1, double Parameter2);
       SampleClass( ); // default constructor
       void do_stuff( );
    Private:
       int data1;
       double data2;
    };

    If you do not want the default constructor to initialize any member variables, then simply give it an empty body by giving it the following definition:

    SampleClass::SampleClass( )
    {
       // This default constructor does nothing but keeps the compiler happy.
    }

  18. The BankAccount class has a constructor with no arguments (in addition to one with two arguments). The correct way to declare an object using the constructor with no arguments is:

    BankAccount account2;

    The following declaration is illegal:
    BankAccount account2( );

    because the compiler will think that this is the prototype of a function called account2 that takes no argument and returns a value of type BankAccount.

    However, if you explicitly call a constructor in an assignment statement, you do need the parentheses:

    account1 = BankAccount( );

    The above assignment statement will set the account balance for account1 to $0.00 and the interest rate to 0.0%.

  19. The following example will illustrate some of the above ideas:

    //Program to demonstrate the class BankAccount.
    #include <iostream.h>

    //Class for a bank account:
    class BankAccount
    {
    public:
        BankAccount(int dollars, int cents, double rate);
        //Initializes the account balance to $dollars.cents and
        //initializes the interest rate to rate percent.

        BankAccount(int dollars, double rate);
        //Initializes the account balance to $dollars.00 and
        //initializes the interest rate to rate percent.

        BankAccount( );
        //Initializes the account balance to $0.00 and the interest rate to 0.0%.

        void update( );
        //Postcondition: One year of simple interest has been added to
        //the account balance.

        double get_balance( );
        //Returns the current account balance.

        double get_rate( );
        //Returns the current account interest rate as a percent.

        void output(ostream& outs);
        //Precondition: If outs is a file output stream, then
        //outs has already been connected to a file.
        //Postcondition: Account balance and interest rate have been
        //written to the stream outs.
    private:
        double balance;
        double interest_rate;

        double fraction(double percent);
        //Converts a percent to a fraction. For example, fraction(50.3)
        //returns 0.503.
    };

    int main( )
    {
        BankAccount account1(100, 2.3), account2;

        cout << "account1 initialized as follows:\n";
        account1.output(cout);
        cout << "account2 initialized as follows:\n";
        account2.output(cout);

        account1 = BankAccount(999, 99, 5.5);
        cout << "account1 reset to the following:\n";
        account1.output(cout);
        return 0;
    }

    BankAccount::BankAccount(int dollars, int cents, double rate)
    {
        balance = dollars + 0.01*cents;
        interest_rate = rate;
    }

    BankAccount::BankAccount(int dollars, double rate)
    {
        balance = dollars;
        interest_rate = rate;
    }

    BankAccount::BankAccount( )
    {
        balance = 0;
        interest_rate = 0.0;
    }

    void BankAccount::update( )
    {
        balance = balance + fraction(interest_rate)*balance;
    }

    double BankAccount::fraction(double percent)
    {
        return (percent/100.0);
    }

    double BankAccount::get_balance( )
    {
        return balance;
    }

    double BankAccount::get_rate( )
    {
        return interest_rate;
    }

    //Uses iostream.h:
    void BankAccount::output(ostream& outs)
    {
        outs.setf(ios::fixed);
        outs.setf(ios::showpoint);
        outs.precision(2);
        outs << "Account balance $" << balance << endl;
        outs << "Interest rate " << interest_rate << "%" << endl;
    }