< Class, Object & Unmanaged Code 2 | Main | Class, Object & Unmanaged Code 4 >


 

 

Object-Oriented Programming:

Class, Object and Unmanaged Code 3

 

 

What do we have in this page?

 

  1. Defining Constructors and Destructors

  2. Defining Constructors

  3. Member Initialization Lists

 

 

Defining Constructors and Destructors

 

In this section, you will see how to define constructor and destructor functions for a class. Let’s start at the beginning with constructors.

 

Defining Constructors

 

A constructor is a special member function that is called automatically when an object is created. The purpose of the constructor is to initialize the object to bring it into an operational state. You declare the prototype for the constructor in the class definition. The following example declares a simple constructor for the CreditCardAccount class:

 

class CreditCardAccount

{

  public:

     CreditCardAccount();

     // ... Other existing members, as before

};

There are several important points to notice here. First, a constructor must have the same name as the class; this is how the compiler recognizes it as a constructor. Also, a constructor cannot specify a return type, not even void. If you do specify a return type for a constructor, you will get a compiler error.

You can implement the constructor in the source file as follows:

CreditCardAccount::CreditCardAccount()

{

    accountNumber = 1234;

    currentBalance = 0;

    creditLimit = 3000;

}

This simple constructor will initialize every new CreditCardAccount object with the same values. A more realistic approach is to define a constructor that takes parameters to allow each object to be initialized with different values. You can provide any number of constructors in a class, as long as each constructor has a distinct parameter list. This is an example of function overloading.

In this exercise, you will add a constructor to your CreditCardAccount class. The constructor will take two parameters specifying the account number and credit limit for the new account. The current balance will always be initialized to 0 for each new account, so there is no need to supply a parameter for this data member.

Continue using the project from the previous exercise.

 

8.        Open CreditCardAccount.h, and declare a public constructor as follows:

class CreditCardAccount

{

    public:

         CreditCardAccount(long number, double limit);

         // ...other existing members...

};

C++ .Net unmanaged class programming - declaring a public constructor source code

Make sure that the constructor is public. If you make it private by mistake, you won’t be able to create CreditCardAccount objects in your program.

9.        Open CreditCardAccount.cpp, and implement the constructor as follows:

CreditCardAccount::CreditCardAccount(long number, double limit)

{

    accountNumber = number;

    creditLimit = limit;

    currentBalance = 0.0;

}

C++ .Net unmanaged class programming - implementing a constructor source code

 

 

 

 

Open CreditOrganizer.cpp. Modify the statement that creates the CreditCardAccount object as follows:

myAccount = new CreditCardAccount(12345, 2500);

C++ .net unmanaged class programming - creating a CreditCardAccount object in the main program source code

This statement creates a new CreditCardAccount object and passes the values 12345 and 2500 into the CreditCardAccount constructor. The constructor uses these parameter values to initialize the accountNumber and creditLimit data members, respectively.

10.     Build the program, and fix any compiler errors.

11.     Run the program. The program now displays meaningful information for the CreditCardAccount object.

 

C++ .net class programming - a console program output sample

 

Member Initialization Lists

 

There’s an alternative syntax for initializing data members in a constructor using a member initialization list as follows:

CreditCardAccount::CreditCardAccount(long number, double limit)

     : accountNumber(number), creditLimit (limit), currentBalance(0.0)

{   }

The colon on the second line is followed by a comma-separated list of data members. For each data member, an initial value is provided in parentheses.

For simple initialization, it doesn’t matter whether you use a member initialization list or simply initialize members in the constructor body. However, there are some situations where you have to use a member initialization list.

 

Defining Destructors

 

A destructor is another special member function that is called automatically when an object is about to be destroyed. The purpose of the destructor is to tidy up the object. For example, the destructor might deallocate additional memory allocated by the object, release resources owned by the object, close database connections opened by the object, and so on.

Only unmanaged classes have destructors. In managed classes, the .NET garbage collector deals with clearing up unused objects; you don’t play a part in object destruction, so you don’t supply a destructor.

You declare the prototype for the destructor in the class definition. The following example declares the destructor for the CreditCardAccount class:

class CreditCardAccount

{

   public:

        ~CreditCardAccount();

        // ... Other existing members, as before

};

The destructor starts with a tilde (~) and has the same name as the class. The destructor does not have a return type and cannot take any parameters. This implies that you can have only one destructor in a class.

You can implement the destructor in the source file as follows:

CreditCardAccount::~CreditCardAccount()

{

    Console::Write("Account being destroyed: ");

    Console::WriteLine(accountNumber);

    Console::Write("Closing balance: ");

    Console::WriteLine(currentBalance);

}

This simple destructor displays status information about a CreditCardAccount object just before it is destroyed.

In this exercise, you will add a destructor to your CreditCardAccount class. The destructor will display a status message describing the object that is being destroyed.

 

1.        Continue using the project from the previous exercise.

2.        Open CreditCardAccount.h, and declare a public destructor as follows:

class CreditCardAccount

{

   public:

      ~CreditCardAccount();

      // ... Other existing members, as before

};

C++ .Net unmanaged class programming - declaring a public destructor in the header file

Make sure the destructor is public, just like the constructor.

3.        Open CreditCardAccount.cpp, and implement the destructor as follows:

CreditCardAccount::~CreditCardAccount()

{

Console::Write("Account being destroyed: ");

Console::WriteLine(accountNumber);

Console::Write("Closing balance: ");

Console::WriteLine(currentBalance);

}

C++ .Net unmanaged class programming - implementing the destructor source code

 

4.        Build the program, and fix any compiler errors.

5.        Run the program. As before, the program creates a CreditCardAccount object, invokes its member functions, and then deletes it. When the CreditCardAccount object is deleted, the destructor is called implicitly to display the closing status of the CreditCardAccount object.

 

C++ .Net programming - new console program output sample

 

Defining Class-Wide Members

 

The data members and member functions currently defined in the CreditCardAccount class are instance members. Each CreditCardAccount instance has its own accountNumber, currentBalance, and creditLimit. Likewise, when you invoke the member functions MakePurchase, MakeRepayment, and PrintStatement, you must specify which CreditCardAccount instance you’re using, as shown in the following figure.

 

C++ .Net unmanaged class programming - class member functions or methods

 

C++ also lets you define class-wide members, which pertain to the entire class rather than to a specific instance. For example, you can define a class-wide data member named numberOfAccounts to count how many CreditCardAccount instances have been created. Similarly, you can provide a class-wide member function named GetNumberOfAccounts to retrieve this count, as shown in the following figure.

 

C++ .Net unmanaged class programming - class wide member function

 

Let’s see how to define class-wide data members and member functions.

 

Defining Class-Wide Data Members

 

To define a class-wide data member, use the static keyword as follows:

class CreditCardAccount

{

   private:

      // Declare class-wide data member

      static int numberOfAccounts;

      // ... Other existing members, as before

};

This declaration tells the compiler that there will be a class-wide data member named numberOfAccounts. This statement also allocates permanent storage for the numberOfAccounts variable. This variable will be available for the entire lifetime of the program, even before any CreditCardAccount objects have been created.

If you do not initialize numberOfAccounts explicitly, the default initial value is 0. If you forget to define numberOfAccounts altogether, you’ll get a link error when you try to build the program. The link error tells you that numberOfAccounts hasn’t been defined.

In this exercise, you will add a static numberOfAccounts data member to the CreditCardAccount class. You will increment this data member every time a new CreditCardAccount object is created.

 

1.        Continue using the project from the previous exercise.

2.        Open CreditCardAccount.h, and declare the static numberOfAccounts data member as follows:

class CreditCardAccount

{

   private:

      static int numberOfAccounts;

      // ... Other existing members, as before

};

C++ .Net unmanaged class programming - declaring the static numberOfAccounts data member

 

3.        Open CreditCardAccount.cpp, and define the numberOfAccounts data member as follows:

int CreditCardAccount::numberOfAccounts = 0;

 

 

 

 

Add this statement after all the #include directives but outside of any function body.

 

C++ .Net unmanaged class programming - defining the numberOfAccounts data member

 

4.   Open CreditCardAccount.cpp, and define the numberOfAccounts data member as follows. Modify the CreditCardAccount constructor so that it increments numberOfAccounts every time a new CreditCardAccount object is created.

CreditCardAccount::CreditCardAccount(long number, double limit)

{

    accountNumber = number;

    creditLimit = limit;

    currentBalance = 0.0;

    numberOfAccounts++;

    Console::Write("Number of accounts created: ");

    Console::WriteLine(numberOfAccounts);

}

C++ .Net class programming - defining the numberOfAccounts data member

 

5.        Open CreditOrganizer.cpp. Modify the main() function so that it creates and uses several CreditCardAccount objects.

Console::WriteLine("Creating first object");

CreditCardAccount * account1;

account1 = new CreditCardAccount(12345, 2000);

account1->MakePurchase(300);

account1->PrintStatement();

Console::WriteLine("\nCreating second object");

CreditCardAccount * account2;

account2 = new CreditCardAccount(67890, 5000);

account2->MakePurchase(750);

account2->PrintStatement();

Console::WriteLine("\nDestroying objects");

delete account1;

delete account2;

C++ .Net unmanaged class programming - creating or instantiating and using several CreditCardAccount objects in the main program

 

6.        Build the program, and fix any compiler errors.

7.        Run the program.

 

Every time a new CreditCardAccount object is created, the program increments numberOfAccounts and displays its latest value.

 

C++ .Net class programming - the updated console program output sample

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5

 

 


< Class, Object & Unmanaged Code 2 | Main | Class, Object & Unmanaged Code 4 >