Class Construction and Destruction |
|
Class Construction |
Method Initializer |
Imagine you are writing a program for a business that sells flowers:
Flower | |||||
Type | Daisies | Lilies | Roses | Live Plants | Tulips |
Color | Mixed | Yellow | Red | Green | Mixed |
Arrangement | Bouquet | Planter Box | Bouquet | Basket | Any |
Price | 35.25 | 115.95 | 85.95 | 60.95 | 58.95 |
Consider the following program:
using namespace System; public value class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; }; int main() { CFlower ^ flr = gcnew CFlower; Console::WriteLine(L"Flower Type: {0}", flr->Type); Console::WriteLine(L"Flower Color: {0}", flr->Color); Console::WriteLine(L"Arrangement: {0}", flr->Arrangement); Console::WriteLine(L"Price: {0:C}", flr->UnitPrice); Console::WriteLine(L""); return 0; }
This would produce:
Flower Type: 0 Flower Color: 0 Arrangement: Price: $0.00 Press any key to continue . . .
If you declare a variable of a class in your program, when the program comes up, the compiler reserves enough memory space for each member of the class. The memory space reserved for each member variable is filled with an initial value based on its type. For a String object, the space would be left empty. For an integer type, the space would be filled with 0. A better way to take care of this type is to provide a value whose role would be to initialize the member variables with the values of your choice. A method that initializes an object can return any value but it is preferable to be of type void because its primary purpose is to reset the values. Since this method would give a starting value to all member variables that need to be initialized, it should have an equivalent argument for each of the member variables that it would initialize. Here is an example:
public value class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; void Initializer(int type, int color, __wchar_t arrange, double price); };
The method initializer doesn't have to initialize all members of the class. For example, the previous execution of the program shows that the member variables that are of type String are initialized with empty strings. In such a case, you may not have to initialize such variables. To implement a method initializer, simply assign its argument to the corresponding member variable of the class. Here are examples:
void CFlower::Initializer(int tp, int clr, __wchar_t arrange, double price) { Type = tp; Color = clr; Arrangement = arrange; UnitPrice = price; }
You can call a method initializer after declaring the instance of the class to give it initial values. Here is an example:
using namespace System; public value class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; void Initializer(int type, int color, __wchar_t arrange, double price); }; void CFlower::Initializer(int tp, int clr, __wchar_t arrange, double price) { Type = tp; Color = clr; Arrangement = arrange; UnitPrice = price; } int main() { CFlower ^ flr = gcnew CFlower; flr->Initializer(3, 7, L'U', 35.85); Console::WriteLine(L"Flower Type: {0}", flr->Type); Console::WriteLine(L"Flower Color: {0}", flr->Color); Console::WriteLine(L"Arrangement: {0}", flr->Arrangement); Console::WriteLine(L"Price: {0:C}", flr->UnitPrice); Console::WriteLine(L""); return 0; } |
This would produce:
Flower Type: 3 Flower Color: 7 Arrangement: U Price: $35.85 Press any key to continue . . .
Using a method initializer, after initializing the object, you can use the values it holds as you see fit.
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { private: long nbr; __wchar_t ^ cat; String ^ mk; String ^ mdl; double discount; double price; public: inline long GetItemNumber(); inline void SetItemNumber(const long number); inline __wchar_t ^ GetCategory(); inline void SetCategory(__wchar_t ^ category); inline String ^ GetMake(); inline void SetMake(String ^ make); inline String ^ GetModel(); inline void SetModel(String ^ model); inline double GetDiscountRate(); inline void SetDiscountRate(const double discountRate); inline double GetUnitPrice(); inline void SetUnitPrice(const double unitPrice); }; } |
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { inline long CStoreItem::GetItemNumber() { return nbr; } inline void CStoreItem::SetItemNumber(const long number) { this->nbr = number; } inline __wchar_t ^ CStoreItem::GetCategory() { return cat; } inline void CStoreItem::SetCategory(__wchar_t ^ category) { this->cat = category; } inline String ^ CStoreItem::GetMake() { return mk; } inline void CStoreItem::SetMake(String ^ make) { this->mk = make; } inline String ^ CStoreItem::GetModel() { return mdl; } inline void CStoreItem::SetModel(String ^ model) { this->mdl = model; } inline double CStoreItem::GetDiscountRate() { return discount / 100; } inline void CStoreItem::SetDiscountRate(const double discountRate) { this->discount = discountRate; } inline double CStoreItem::GetUnitPrice() { return price; } inline void CStoreItem::SetUnitPrice(const double unitPrice) { this->price = unitPrice; } } |
#include "StoreItem.h" using namespace System; using namespace ElectronicsStore; static void DescribeStoreItem(CStoreItem ^ %); int main() { String ^ strTitle = L"=-= Nearson Electonics =-=\n" L"******* Store Items ******"; Console::WriteLine(); return 0; } void DescribeStoreItem(CStoreItem ^ %item) { Console::WriteLine(L"Store Item Description"); Console::WriteLine(L"Item Number: {0}", item->GetItemNumber()); Console::WriteLine(L"Category: {0}", item->GetCategory()); Console::WriteLine(L"Make {0}", item->GetMake()); Console::WriteLine(L"Model: {0}", item->GetModel()); Console::WriteLine(L"Discount Rate: {0:P}", item->GetDiscountRate()); Console::WriteLine(L"Unit Price: {0:C}", item->GetUnitPrice()); } |
A constructor is a special method that is created when the object comes to life. This particular method holds the same name as that of the class and it initializes the object whenever that object is created. Unlike some of the other methods, the constructor does not return a value, not even void. When you create a class, if you don't declare a constructor, the compiler would create one for you; this is useful because it lets all other objects and functions of the program know that the object exists. This compiler-created constructor is called the default constructor. If you want, you can create your own constructor. To create a constructor, declare a method that holds the same name as the class. Remember that the method must not return any value. Besides that, the second rule is that the class must be created with the ref instead of the value keywords. |
Here is an example:
public ref class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; CFlower(); };
When you declare an instance of the class, whether you use that object or not, a constructor for the object is created and signals itself. When an instance of a class has been declared, the default constructor is called, whether the object is used or not. This is illustrated in the following program:
using namespace System; public ref class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; CFlower(); }; CFlower::CFlower() { Console::WriteLine("An order has been placed!!!"); } int main() { CFlower ^ flr = gcnew CFlower; Console::WriteLine(L""); return 0; }
This would produce:
An order has been placed!!! Press any key to continue...
As you can see, even though the flr variable was not used, just its declaration was enough to signal it. You might find it sometimes convenient to create your own constructor because, whether you create an empty constructor or not, this does not negatively impact your program.
When declaring an instance of a class using the default constructor, you can use or omit the parentheses. The effect is the same. Therefore, you can declare a CFlower variable as follows:
int main() { CFlower ^ flr = gcnew CFlower(); Console::WriteLine(L""); return 0; }
Also, remember that, in C++, if a method doesn't take an argument, when declaring and defining the method, you can type void in its parentheses:
public ref class CFlower { public: int Type; int Color; __wchar_t Arrangement; double UnitPrice; Flower(void); }; Flower::Flower(void) { }
Practical Learning: Using the Default Constructor |
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { public: CStoreItem(void); private: long nbr; __wchar_t ^ cat; String ^ mk; String ^ mdl; double discount; double price; public: . . . No Change }; } |
The Constructor Initializer |
A constructor can be used to initialize the member variables of a class. As such, a constructor provides a valuable alternative to a method initializer, the type of method we saw earlier. To use a constructor to initialize the member variables of a class, provide as arguments the necessary variables that you intend to initialize. You don't have to initialize all member variables in the constructor, only those that need to be initialized. In fact, you should initialize only those members that you think the other objects or functions would need when using this object. This means that your object may have member variables that, either the external objects or functions don't need to modify (or access) or the member variable(s) will be initialized later when called from the needed object(s) or function(s).
To implement a default constructor, you can just initialize the desired members of the class. For a member variable of a numeric type, you can just assign the desired constant to each. Here is an example:
CFlower::CFlower(void) { Type = 1; }
If the variable is a character, assign a single-quoted symbol to it. If the variable is a string, then assign a double-quoted value to the variable. Here are examples:
using namespace System; public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower(); }; CFlower::CFlower() { Type = L"Roses"; Color = L"Red"; Arrangement = L"Basket"; UnitPrice = 45.95; } |
int main() { CFlower ^ flr = gcnew CFlower; Console::WriteLine(L"Flower Type: {0}", flr->Type); Console::WriteLine(L"Flower Color: {0}", flr->Color); Console::WriteLine(L"Arrangement: {0}", flr->Arrangement); Console::WriteLine(L"Price: {0:C}", flr->UnitPrice); Console::WriteLine(L""); return 0; }
This would produce:
Flower Type: Roses Flower Color: Red Arrangement: Basket Price: $45.95 Press any key to continue . . .
If the member is a handle to a class, make sure you initialize it prior to using it.
Practical Learning: Initializing Using the Default Constructor |
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { CStoreItem::CStoreItem(void) { nbr = 0; cat = L'U'; mk = L"Unknown"; mdl = L"Unspecified"; discount = 0.00; price = 0.00; } . . . No Change } |
#include "StoreItem.h" using namespace System; using namespace ElectronicsStore; static void DescribeStoreItem(CStoreItem ^ %); int main() { String ^ strTitle = L"=-= Nearson Electonics =-=\n" L"******* Store Items ******"; CStoreItem ^ saleItem = gcnew CStoreItem(); DescribeStoreItem(saleItem); Console::WriteLine(); return 0; } void DescribeStoreItem(CStoreItem ^ %item) { Console::WriteLine(L"Store Item Description"); Console::WriteLine(L"Item Number: {0}", item->GetItemNumber()); Console::WriteLine(L"Category: {0}", item->GetCategory()); Console::WriteLine(L"Make {0}", item->GetMake()); Console::WriteLine(L"Model: {0}", item->GetModel()); Console::WriteLine(L"Discount Rate: {0:P}", item->GetDiscountRate()); Console::WriteLine(L"Unit Price: {0:C}", item->GetUnitPrice()); } |
Store Item Description Item Number: 0 Category: U Make Unknown Model: Unspecified Discount Rate: 0.00 % Unit Price: $0.00 Press any key to continue . . . |
The default constructor is the favorite place to provide default values to the members of a class. Besides the default constructor, you can add as many constructors as you judge necessary. This feature of C++ allows you to create various constructors for different reasons. This also means that, like ordinary functions, the methods or constructors of a class can be overloaded.
One of the rules of function overloading consists of having functions with different types of arguments. The most basic constructor you would create can use a single argument. When implementing a constructor that takes one argument, you should initialize the member that corresponds to the unique argument and initialize the other members with default values. Here is an example:
public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower(String ^ type); }; CFlower::CFlower(String ^ type) { Type = type; Color = L"Red"; Arrangement = L"Basket"; UnitPrice = 35.95; }
If you create a class with only one constructor as in the current example, when declaring an instance of the class, you must use that constructor: you cannot use the default constructor that doesn't take an argument. When declaring the variable, initialize it with a constructor with parentheses and provide the value(s) in the parentheses of the constructor. Here is an example:
using namespace System; public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower(String ^ type); }; CFlower::CFlower(String ^ type) { Type = type; Color = L"Red"; Arrangement = L"Basket"; UnitPrice = 35.95; } int main() { CFlower ^ flr = gcnew CFlower(L"Tulip"); Console::WriteLine(L"Flower Type: {0}", flr->Type); Console::WriteLine(L"Flower Color: {0}", flr->Color); Console::WriteLine(L"Arrangement: {0}", flr->Arrangement); Console::WriteLine(L"Price: {0:C}", flr->UnitPrice); Console::WriteLine(L""); return 0; }
This would produce:
Flower Type: Tulip Flower Color: Red Arrangement: Basket Price: $35.95 Press any key to continue . . .
In the same way, you can create different constructors for different initializations, although it would not be realistic to create a different constructor for each variable. If you create different constructors with different arguments to initialize (remember the rules of function overloading), when declaring the classes, make sure you initialize each instance with the right number of arguments; otherwise, the compiler may complain.
If you create a class with only one constructor and that constructor has at least one argument, the default constructor would not be available anymore. If you want to access a default constructor of an object, you have two alternatives:
Practical Learning: Overloading the Constructor |
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { public: // An item whose characteristics are not (yet) known CStoreItem(void); // An item that is known by its make, model, and unit price CStoreItem(long itmNbr, String ^ make, String ^ model, double unitPrice); // An item that is known by its name and unit price CStoreItem(long itmNbr, String ^ name, double unitPrice); private: long nbr; __wchar_t ^ cat; String ^ mk; String ^ mdl; String ^ nm; double discount; double price; public: inline long GetItemNumber(); inline void SetItemNumber(const long number); inline __wchar_t ^ GetCategory(); inline void SetCategory(__wchar_t ^ category); inline String ^ GetMake(); inline void SetMake(String ^ make); inline String ^ GetModel(); inline void SetModel(String ^ model); inline String ^ GetName(); inline void SetName(String ^ name); inline double GetDiscountRate(); inline void SetDiscountRate(const double discountRate); inline double GetUnitPrice(); inline void SetUnitPrice(const double unitPrice); }; } |
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { CStoreItem::CStoreItem(void) { nbr = 0; cat = L'U'; mk = L"Unknown"; mdl = L"Unspecified"; nm = L"N/A"; discount = 0.00; price = 0.00; } CStoreItem::CStoreItem(long itmNbr, String ^ make, String ^ model, double unitPrice) { nbr = itmNbr; cat = L'U'; mk = make; mdl = model; nm = L"N/A"; discount = 0.00; price = unitPrice; } CStoreItem::CStoreItem(long itmNbr, String ^ name, double unitPrice) { nbr = itmNbr; cat = L'U'; mk = L"Unknown"; mdl = L"Unspecified"; nm = name; discount = 0.00; price = unitPrice; } inline long CStoreItem::GetItemNumber() { return nbr; } inline void CStoreItem::SetItemNumber(const long number) { this->nbr = number; } inline __wchar_t ^ CStoreItem::GetCategory() { return cat; } inline void CStoreItem::SetCategory(__wchar_t ^ category) { this->cat = category; } inline String ^ CStoreItem::GetMake() { return mk; } inline void CStoreItem::SetMake(String ^ make) { this->mk = make; } inline String ^ CStoreItem::GetModel() { return mdl; } inline void CStoreItem::SetModel(String ^ model) { this->mdl = model; } inline String ^ CStoreItem::GetName() { return nm; } inline void CStoreItem::SetName(String ^ name) { name = nm; } inline double CStoreItem::GetDiscountRate() { return discount / 100; } inline void CStoreItem::SetDiscountRate(const double discountRate) { this->discount = discountRate; } inline double CStoreItem::GetUnitPrice() { return price; } inline void CStoreItem::SetUnitPrice(const double unitPrice) { this->price = unitPrice; } } |
#include "StoreItem.h" using namespace System; using namespace ElectronicsStore; static void DescribeStoreItem(CStoreItem ^ %); int main() { String ^ strTitle = L"=-= Nearson Electonics =-=\n" L"******* Store Items ******"; CStoreItem ^ saleItem = gcnew CStoreItem(); Console::WriteLine(L"==/==A store item with default values==/=="); DescribeStoreItem(saleItem); Console::WriteLine(); saleItem = gcnew CStoreItem(606302, L"Altec Lansing", L"AHP-712I", 85.95); saleItem->SetCategory(L'H'); saleItem->SetDiscountRate(25); Console::WriteLine(L"==/==A store item known for its make, " L"model, and unit price==/=="); DescribeStoreItem(saleItem); Console::WriteLine(); Console::WriteLine(L"==/==A store item with default values==/=="); saleItem = gcnew CStoreItem(162864, L"External Sound Card", 85.95); DescribeStoreItem(saleItem); Console::WriteLine(); Console::WriteLine(L"==/==A store item completely defined==/=="); saleItem = gcnew CStoreItem(513497, L'T', L"Uniden", L"8x8 Packet8 Broadband Internet Phone System", 10, 145.95); DescribeStoreItem(saleItem); Console::WriteLine(); Console::WriteLine(L"==/==A store item with each " L"characteristic defined==/=="); saleItem = gcnew CStoreItem(); saleItem->SetItemNumber(913846); saleItem->SetCategory(L'S'); saleItem->SetMake(L"APC"); saleItem->SetModel(L"Personal SurgeArrest"); saleItem->SetDiscountRate(25.00); saleItem->SetUnitPrice(14.95); DescribeStoreItem(saleItem); Console::WriteLine(); return 0; } void DescribeStoreItem(CStoreItem ^ %item) { Console::WriteLine(L"Store Item Description"); Console::WriteLine(L"Item Number: {0}", item->GetItemNumber()); Console::WriteLine(L"Category: {0}", item->GetCategory()); Console::WriteLine(L"Make {0}", item->GetMake()); Console::WriteLine(L"Model: {0}", item->GetModel()); Console::WriteLine(L"Name: {0}", item->GetName()); Console::WriteLine(L"Discount Rate: {0:P}", item->GetDiscountRate()); Console::WriteLine(L"Unit Price: {0:C}", item->GetUnitPrice()); } |
==/==A store item with default values==/== Store Item Description Item Number: 0 Category: U Make Unknown Model: Unspecified Name: N/A Discount Rate: 0.00 % Unit Price: $0.00 |
|
==/==A store item known for its make, model, and unit price==/== Store Item Description Item Number: 606302 Category: H Make Altec Lansing Model: AHP-712I Name: N/A Discount Rate: 25.00 % Unit Price: $85.95 |
|
==/==A store item with default values==/== Store Item Description Item Number: 162864 Category: U Make Unknown Model: Unspecified Name: External Sound Card Discount Rate: 0.00 % Unit Price: $85.95 |
|
==/==A store item completely defined==/== Store Item Description Item Number: 513497 Category: T Make Uniden Model: 8x8 Packet8 Broadband Internet Phone System Name: Discount Rate: 10.00 % Unit Price: $145.95 |
|
==/==A store item with each characteristic defined==/== Store Item Description Item Number: 913846 Category: S Make APC Model: Personal SurgeArrest Name: N/A Discount Rate: 25.00 % Unit Price: $14.95 |
Techniques of Initializing With a Constructor |
By now, we saw that methods can be implemented inline, that is, in the body of a class. This also applies to constructors:
public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower() { Type = L"Roses"; Color = L"Red"; Arrangement = L"Basket"; UnitPrice = 45.95; } CFlower(String ^ type); };
C++ provides another technique you can use to initialize the member variables in a constructor. To initialize the list of members, after defining the constructor, which is after the parentheses, type a colon, followed by the name of an argument and include its initial value in parentheses. The initializations are separated by a comma. Since the constructor is a method, make sure you provide its body. Here are examples:
public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower() : Type(L"Roses"), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(35.95) { } CFlower(String ^ type); }; CFlower::CFlower(String ^ type) : Type(type), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(45.95) { }
You can still use the initialization that consists of assigning a value to the desired member variable. Still, observe the rules when declaring a variable of the class:
#include <iostream> using namespace std; using namespace System; public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower() : Type(L"Roses"), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(45.95) { } CFlower(String ^ type); CFlower(String ^ type, String ^ color, String ^ argn, double price); }; CFlower::CFlower(String ^ type) : Type(type), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(35.95) { } CFlower::CFlower(String ^ type, String ^ color, String ^ argn, double price) { Type = type; Color = color; Arrangement = argn; UnitPrice = price; } void Show(const CFlower ^ flower) { Console::WriteLine(L"Flower Type: {0}", flower->Type); Console::WriteLine(L"Flower Color: {0}", flower->Color); Console::WriteLine(L"Arrangement: {0}", flower->Arrangement); Console::WriteLine(L"Price: {0:C}", flower->UnitPrice); } int main() { // Using the default constructor CFlower ^ flower = gcnew CFlower; Show(flower); Console::Write(L"\nPress any key to continue..."); Console::ReadLine(); system("cls"); // Using the constructor with one argument flower = gcnew CFlower(L"Tulip"); Show(flower); Console::Write(L"\nPress any key to continue..."); Console::ReadLine(); system("cls"); // Using a full constructor flower = gcnew CFlower(L"Lilies", L"Pink", L"Bouquet", 45.65); Console::WriteLine(L""); return 0; }
This would produce:
Screen 1 |
Flower Type: Roses Flower Color: Red Arrangement: Basket Price: $35.95 Press any key to continue... |
Screen 2 |
Flower Type: Tulip Flower Color: Red Arrangement: Basket Price: $35.95 Press any key to continue... |
Screen 3 |
Flower Type: Lilies Flower Color: Pink Arrangement: Bouquet Price: $45.65 Press any key to continue . . . |
Practical Learning: Initializing With the Constructors |
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { CStoreItem::CStoreItem(void) : nbr(0), cat(L'U'), mk(L"Unknown"), mdl(L"Unspecified"), nm(L"N/A"), discount(0.00), price(0.00) { } CStoreItem::CStoreItem(long itmNbr, String ^ make, String ^ model, double unitPrice) : nbr(itmNbr), cat(L'U'), mk(make), mdl(model), nm(L"N/A"), discount(0.00), price(unitPrice) { } CStoreItem::CStoreItem(long itmNbr, String ^ name, double unitPrice) : nbr(itmNbr), cat(L'U'), mk(L"Unknown"), mdl(L"Unspecified"), nm(name), discount(0.00), price(unitPrice) { } CStoreItem::CStoreItem(long itmNbr, __wchar_t category, String ^ make, String ^ model, double discountRate, double unitPrice) : nbr(itmNbr), cat(category), mk(make), mdl(model), discount(discountRate), price(unitPrice) { } . . . No Change } |
Copying an Object |
After creating an object and assigning appropriate values to its member variables, you can perform any regular operation on it. We have already learned:
How to assign | Example |
A value to a variable | int a = 250; |
The value of one variable to another | NbrOfBoys = NbrOfGirls; |
A value to an object’s member | Video.Category = L 'H' |
Assigning a variable to another is equivalent to making a copy of that variable. As you assign a variable to another, you can assign one object to another. Both objects must be recognizably equivalent types to the compiler. Here is an example:
int main() { CFlower ^ flower = gcnew CFlower(L"Lilies", L"Pink", L"Bouquet", 45.65); Show(flower); Console::WriteLine(L""); CFlower ^ inspiration; inspiration = flower; Show(inspiration); Console::WriteLine(L""); return 0; }
This would produce:
Flower Type: Lilies Flower Color: Pink Arrangement: Bouquet Price: $45.65 Flower Type: Lilies Flower Color: Pink Arrangement: Bouquet Price: $45.65 Press any key to continue . . .
Notice that both orders display the same thing.
Using a Copy Constructor |
Besides the default constructor, the compiler creates another method called the copy constructor. This constructor is used for operations such as copying an object into another. Remember, we have seen that a variable could be initialized using the = symbol or the parentheses. When you have two instances of a class such as: CFlower ^ Inspiration, ^ Elegance; you can assign one object to another like this: Elegance = Inspiration; This operation indeed assigns a copy of the Inspiration flower to the Elegance object. Behind the scenes, this transaction is handled by the copy constructor. Like the default constructor, the compiler automatically creates a copy constructor when an object is instantiated. Like the default constructor, you can explicitly create a copy constructor; it has a different syntax although it also holds the same name as the class. The syntax of the copy constructor. ClassName(ObjectName ^ & Name); |
The copy constructor takes one argument, which is the same as the class itself. When a copy is made, it holds and carries the building construction of the object. This object is specified as the argument. As a copy whose value still resides with the object, this argument should be passed as a reference and it should not be modified. It is only used to pass a copy of the object to the other objects that need it. Therefore, the argument should not be modified. As a result, it should be declared as a constant. The syntax of the copy constructor becomes:
ClassName(const ClassName^ & Name);
To copy one object to another, first create a copy constructor:
public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower() : Type(L"Roses"), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(35.95) { } CFlower(String ^ type); CFlower(String ^ type, String ^ color, String ^ argn, double price); CFlower(const CFlower ^ &copier); };
To implement the copy constructor, at a minimum, assign a member variable of the copy constructor to the equivalent member of the object:
CFlower::CFlower(const CFlower ^ &copier) { Type = copier->Type; Color = copier->Color; Arrangement = copier->Arrangement; UnitPrice = copier->UnitPrice; }
In some cases, instead of a one-to-one assignment of member variables from one object to another, you can change how the target object would receive the values.
Introduction |
As opposed to a constructor, a destructor is called when a program has finished using an object. A destructor does the cleaning behind the scenes. Like the default constructor, the compiler always creates a default destructor if you don't create one. Unlike the constructor, the destructor cannot be overloaded. This means that, if you decide to create a destructor, you can have only one. Like the default constructor, a destructor also has the same name as its class. This time, the name of the destructor starts with a tilde.
To create a destructor, type ~ followed by the name of the class. Here is an example:
public ref class CFlower { public: String ^ Type; String ^ Color; String ^ Arrangement; double UnitPrice; CFlower() : Type(L"Roses"), Color(L"Red"), Arrangement(L"Basket"), UnitPrice(35.95) { } CFlower(String ^ type); CFlower(String ^ type, String ^ color, String ^ argn, double price); CFlower(const CFlower ^ &copier); ~CFlower(); }; |
Practical Learning: Creating a Destructor |
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { public: // An item whose characteristics are not (yet) known CStoreItem(void); // An item that is known by its make, model, and unit price CStoreItem(long itmNbr, String ^ make, String ^ model, double unitPrice); // An item that is known by its name and unit price CStoreItem(long itmNbr, String ^ name, double unitPrice); // An item completely defined CStoreItem(long itmNbr, __wchar_t category, String ^ make, String ^ model, double discountRate, double unitPrice); ~CStoreItem(); private: . . . No Change }; } |
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { . . . No Change CStoreItem::CStoreItem(long itmNbr, __wchar_t category, String ^ make, String ^ model, double discountRate, double unitPrice) : nbr(itmNbr), cat(category), mk(make), mdl(model), discount(discountRate), price(unitPrice) { } CStoreItem::~CStoreItem() { } . . . No Change } |
Object Destruction in the Native Heap |
As done with a default constructor, you may not need to do anything in the implementation of a destructor. In fact, when a program terminates, the compiler can itself destroy all of the objects and variables that your program had used. However, if you dynamically create some variable in the constructor(s), using pointers, you can then delete or destroy them in the destructor. If the variables were created as regular pointers, you can use the delete operator.
Object Destruction and the Managed Heap |
In C++/CLI, if you create a handle, the compiler would take care of destroying it when the program terminates. This is the role of the garbage collector. It determines when the object is not needed anymore instead of you taking care of it. Still, if you want, you can create a handle in a constructor and destroy it the destructor, using the delete operator. Here is an example:
Header File: Circle.h |
#pragma once namespace Geometry { public ref class CCircle { public: CCircle(); ~CCircle(); double ^ Radius; double Area(); literal double Pi = 3.14159; }; } |
Source File: Circle.cpp |
#include "circle.h" namespace Geometry { CCircle::CCircle() { Radius = gcnew double(0.00); } CCircle::~CCircle() { delete Radius; } double CCircle::Area() { return *Radius * *Radius * Pi; } } |
Source File: Exercise.cpp |
#include "Circle.h" using namespace System; using namespace Geometry; CCircle ^ CreateCircle() { Console::Write(L"Enter the radius of the circle: "); double ^ rad = double::Parse(Console::ReadLine()); CCircle ^ circle = gcnew CCircle(); circle->Radius = rad; return circle; } void DescribeCircle(CCircle ^ round) { Console::WriteLine(L"Circle Description"); Console::WriteLine(L"Radius: {0:F}", round->Radius); Console::WriteLine(L"Area: {0:F}", round->Area()); } int main() { CCircle ^ figure = CreateCircle(); Console::WriteLine(); DescribeCircle(figure); Console::WriteLine(); return 0; } |
Here is an example of running the program:
Enter the radius of the circle: 48.12 Circle Description Radius: 48.12 Area: 7274.46 Press any key to continue . . .
|
||
Previous | Copyright © 2006-2016, FunctionX, Inc. | Next |
|