Returning a Class Type
|
Returning a Tracking Reference
|
As done for regular types, you
can return a tracking reference to a class.
To indicate this, type the % operator
between the class type and the name of the function. In the body of the function, you can create a
class as complete as possible, get a tracking reference to that class, and
return that reference. Here is an example:
|
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; CCar % Build(); int main() { CCar ^ vehicle = Build(); Console::WriteLine(L"Car Characteristics"); Console::WriteLine(L"Make: {0}", vehicle->Make); Console::WriteLine(L"Model: {0}", vehicle->Model); Console::WriteLine(L"Doors: {0}", vehicle->Doors); Console::WriteLine(L"Year: {0}", vehicle->Year); Console::WriteLine(L"Value: {0:C}", vehicle->Price); Console::WriteLine(); return 0; } CCar % Build() { CCar car; Console::Write(L"Enter Make: "); car.Make = Console::ReadLine(); Console::Write(L"Enter Model: "); car.Model = Console::ReadLine(); Console::Write(L"# of Doors: "); car.Doors = int::Parse(Console::ReadLine()); Console::Write(L"Year Made: "); car.Year = int::Parse(Console::ReadLine()); Console::Write(L"Enter Price: "); car.Price = double::Parse(Console::ReadLine()); CCar % veh = car; return veh; }
This would produce:
Enter Make: Honda Enter Model: Accord # of Doors: 4 Year Made: 1998 Enter Price: 14500 Car Characteristics Make: Honda Model: Accord Doors: 4 Year: 1998 Value: $14,500.00 Press any key to continue . . .
|
- To start a new program, launch Microsoft Visual C++ 2005
- On the main menu, click File -> New -> Project...
- On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
- In the Name box, replace the string with RealEstate10 and click OK
- On the main menu, click Project -> Add New Item...
- To create a header file, in the Templates list, click Header File (.h)
- Set the Name to Property and click Add
- Complete the file as follows:
#pragma once using namespace System; namespace RealEstate { public ref class CProperty { public: long PropertyNumber; String ^ Address; String ^ City; String ^ State; String ^ ZIPCode; int Bedrooms; float Bathrooms; int YearBuilt; double MarketValue; }; }
- To create another header file, on the main menu, click Project -> Add New Item...
- In the Templates list, make sure Header File (.h) is selected.
Set the Name to House and press Enter - Complete the file as follows:
#pragma once #include "Property.h" using namespace System; namespace RealEstate { public ref class CHouse : public CProperty { public: Byte Stories; int Condition; unsigned NumberOfGarageSpaces; }; }
- To create one more header file, on the main menu, click Project -> Add New Item...
- In the Templates list, make sure Header File (.h) is selected.
Set the Name to SingleFamily and click Add - Complete the file as follows:
#pragma once #include "House.h" using namespace System; namespace RealEstate { public ref class CSingleFamily : public CHouse { public: __wchar_t Style; double LotSizeInSqFt; }; }
- To create a source file, on the main menu, click Project -> Add New Item...
- In the Templates list, click C++ File (.cpp)
- In the New box, type Exercise and click Add
- In the empty file, type:
#include <iostream> #include "SingleFamily.h" using namespace std; using namespace RealEstate; int main() { String ^ strTitle1 = L"=//= Altair Realty =//="; String ^ strTitle2 = L"-=- Properties Inventory -=-"; CSingleFamily ^ home = gcnew CSingleFamily; Console::WriteLine(strTitle1); Console::WriteLine(strTitle2); Console::WriteLine(); return 0; }
- Execute the application to test it
- Close the DOS window
Returning a Handle
|
If you are defining a function and you want it to return a
handle to a class, you can. To indicate this, between the name of the class and
the name of the function, type the ^ operator.
|
- To return a handle, change the Exercise.cpp file as follows:
#include <iostream> #include "SingleFamily.h" using namespace std; using namespace RealEstate; CSingleFamily ^ CreateListing() { CSingleFamily ^ home = gcnew CSingleFamily; Console::WriteLine("To create a listing, enter the following information"); Console::Write("Property #: "); home->PropertyNumber = long::Parse(Console::ReadLine()); Console::WriteLine("Property Condition"); Console::WriteLine("0. Unknown"); Console::WriteLine("1. Excellent"); Console::WriteLine("2. Good (may need minor repair"); Console::WriteLine("3. Acceptable (needs major repair)"); Console::WriteLine("4. Even (land is more important)"); Console::Write("Your Choice: "); home->Condition = int::Parse(Console::ReadLine()); Console::Write("Street Address: "); home->Address = Console::ReadLine(); Console::Write("City: "); home->City = Console::ReadLine(); Console::Write("State: "); home->State = Console::ReadLine(); Console::Write("ZIP Code: "); home->ZIPCode = Console::ReadLine(); Console::Write("Bedrooms: "); home->Bedrooms = int::Parse(Console::ReadLine()); Console::Write("Bathrooms: "); home->Bathrooms = float::Parse(Console::ReadLine()); Console::Write("Stories: "); home->Stories = int::Parse(Console::ReadLine()); Console::Write("Year Built: "); home->YearBuilt = int::Parse(Console::ReadLine()); Console::WriteLine("Style"); Console::WriteLine("U. Unknown"); Console::WriteLine("S. Split Level"); Console::WriteLine("C. Colonial"); Console::WriteLine("G. Georgial"); Console::Write("Your Choice: "); home->Style = __wchar_t::Parse(Console::ReadLine()); Console::Write("Garage Spaces: "); home->NumberOfGarageSpaces = int::Parse(Console::ReadLine()); Console::Write("Total Lot Size: "); home->LotSizeInSqFt = double::Parse(Console::ReadLine()); Console::Write("Market Value: "); home->MarketValue = double::Parse(Console::ReadLine()); return home; } int main() { String ^ strTitle1 = L"=//= Altair Realty =//="; String ^ strTitle2 = L"-=- Properties Inventory -=-"; CSingleFamily ^ house = CreateListing(); system("cls"); Console::WriteLine(strTitle1); Console::WriteLine(strTitle2); Console::WriteLine("=//= Property Listing =//="); Console::WriteLine("Property #: {0}", house->PropertyNumber); Console::WriteLine("Address: {0}\n {1}, {2} {3}", house->Address, house->City, house->State, house->ZIPCode); Console::WriteLine("Condition: {0}", house->Condition); Console::WriteLine("Style: {0}", house->Style); Console::WriteLine("Bedrooms: {0}", house->Bedrooms); Console::WriteLine("Bathrooms: {0}", house->Bathrooms); Console::WriteLine("Stories: {0}", house->Stories); Console::WriteLine("Year Built: {0}", house->YearBuilt); Console::WriteLine("Garage Spaces: {0} SqFt", house->NumberOfGarageSpaces); Console::WriteLine("Lot Size: {0:F}", house->LotSizeInSqFt); Console::WriteLine("Market Value: {0:C}", house->MarketValue); Console::WriteLine(); return 0; }
- Execute the application to test it
- Close the DOS window
Passing a Class Type
|
Passing a Tracking Reference
|
Like a regular data type, a class can be passed to a
function as argument. You can pass an argument as a tracking reference. To do
this, in the parentheses of the function, type the name of the class, followed
by the % operator, followed by a name for the argument. This would be done as
follows:
void DescribeProperty(CHouse % home);
In the body of the function, you can either ignore the
argument and not use it at all, or you can process or use the argument as you
see fit. At a minimum, you can retrieve the values of its member variables,
using the period operator. As mentioned for the regular types, when (only) declaring a function
that takes a class type as argument, you can omit the name of the argument.
When calling the function, pass the argument with the *
operator. Here is an example:
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; CCar % Build(); void Show(CCar % car); int main() { Console::WriteLine(L"Enter Car Information"); CCar ^ vehicle = Build(); Console::WriteLine(L"\nCar Characteristics"); Show(*vehicle); Console::WriteLine(); return 0; } CCar % Build() { CCar car; Console::Write(L"Enter Make: "); car.Make = Console::ReadLine(); Console::Write(L"Enter Model: "); car.Model = Console::ReadLine(); Console::Write(L"# of Doors: "); car.Doors = int::Parse(Console::ReadLine()); Console::Write(L"Year Made: "); car.Year = int::Parse(Console::ReadLine()); Console::Write(L"Enter Price: "); car.Price = double::Parse(Console::ReadLine()); CCar % veh = car; return veh; } void Show(CCar % car) { Console::WriteLine(L"Make: {0}", car.Make); Console::WriteLine(L"Model: {0}", car.Model); Console::WriteLine(L"Doors: {0}", car.Doors); Console::WriteLine(L"Year: {0}", car.Year); Console::WriteLine(L"Value: {0:C}", car.Price); }
In the same way, you can pass as many tracking references as you want to
a function.
If a function doesn't modify an argument, you can pass it as
a constant. This also applies to tracking references. Here is an example:
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; CCar % Build(); void Show(const CCar % car); int main() { Console::WriteLine(L"Enter Car Information"); CCar ^ vehicle = Build(); Console::WriteLine(L"\nCar Characteristics"); Show(*vehicle); Console::WriteLine(); return 0; } CCar % Build() { CCar car; . . . CCar % veh = car; return veh; } void Show(const CCar % car) { . . . }
Passing a Handle
|
Another technique you can use to pass a class by reference
is to pass it as a handle. To start with the formula we reviewed, use the ^
operator instead of %. In the body of the function, you can access each member
variable using the -> operator.
As mentioned for a tracking reference, if the function
doesn't modify the argument, the handle can be passed as a constant.
Using handles as arguments, you can overload a function by
creating functions with the same name with either different types of argument(s) or different
numbers of arguments.
|
- To pass a handle as argument, change the Exercise.cpp file as follows:
#include <iostream> #include "SingleFamily.h" using namespace std; using namespace RealEstate; CSingleFamily ^ CreateListing() { CSingleFamily ^ home = gcnew CSingleFamily; Console::WriteLine("To create a listing, " enter the following information"); Console::Write("Property #: "); home->PropertyNumber = long::Parse(Console::ReadLine()); Console::WriteLine("Property Condition"); Console::WriteLine("0. Unknown"); Console::WriteLine("1. Excellent"); Console::WriteLine("2. Good (may need minor repair"); Console::WriteLine("3. Acceptable (needs major repair)"); Console::WriteLine("4. Even (land is more important)"); Console::Write("Your Choice: "); home->Condition = int::Parse(Console::ReadLine()); Console::Write("Street Address: "); home->Address = Console::ReadLine(); Console::Write("City: "); home->City = Console::ReadLine(); Console::Write("State: "); home->State = Console::ReadLine(); Console::Write("ZIP Code: "); home->ZIPCode = Console::ReadLine(); Console::Write("Bedrooms: "); home->Bedrooms = int::Parse(Console::ReadLine()); Console::Write("Bathrooms: "); home->Bathrooms = float::Parse(Console::ReadLine()); Console::Write("Stories: "); home->Stories = int::Parse(Console::ReadLine()); Console::Write("Year Built: "); home->YearBuilt = int::Parse(Console::ReadLine()); Console::WriteLine("Style"); Console::WriteLine("U. Unknown"); Console::WriteLine("S. Split Level"); Console::WriteLine("C. Colonial"); Console::WriteLine("G. Georgial"); Console::Write("Your Choice: "); home->Style = __wchar_t::Parse(Console::ReadLine()); Console::Write("Garage Spaces: "); home->NumberOfGarageSpaces = int::Parse(Console::ReadLine()); Console::Write("Total Lot Size: "); home->LotSizeInSqFt = double::Parse(Console::ReadLine()); Console::Write("Market Value: "); home->MarketValue = double::Parse(Console::ReadLine()); return home; } void ShowProperty(const CSingleFamily ^ home) { Console::WriteLine("=//= Property Listing =//="); Console::WriteLine("Property #: {0}", home->PropertyNumber); Console::WriteLine("Address: {0}\n {1}, {2} {3}", home->Address, home->City, home->State, home->ZIPCode); Console::WriteLine("Condition: {0}", home->Condition); Console::WriteLine("Style: {0}", home->Style); Console::WriteLine("Bedrooms: {0}", home->Bedrooms); Console::WriteLine("Bathrooms: {0}", home->Bathrooms); Console::WriteLine("Stories: {0}", home->Stories); Console::WriteLine("Year Built: {0}", home->YearBuilt); Console::WriteLine("Garage Spaces: {0} SqFt", home->NumberOfGarageSpaces); Console::WriteLine("Lot Size: {0:F}", home->LotSizeInSqFt); Console::WriteLine("Market Value: {0:C}", home->MarketValue); } int main() { String ^ strTitle1 = L"=//= Altair Realty =//="; String ^ strTitle2 = L"-=- Properties Inventory -=-"; CSingleFamily ^ house = CreateListing(); system("cls"); Console::WriteLine(strTitle1); Console::WriteLine(strTitle2); ShowProperty(house); Console::WriteLine(); return 0; }
- Execute the application and test it. Here is an example:
Screen 1 To create a listing, enter the following information Property #: 530955 Property Condition 0. Unknown 1. Excellent 2. Good (may need minor repair 3. Acceptable (needs major repair) 4. Even (land is more important) Your Choice: 3 Street Address: 7244 Lemson Drive City: Alexandria State: VA ZIP Code: 22231 Bedrooms: 3 Bathrooms: 1.5 Stories: 1 Year Built: 1954 Style U. Unknown S. Split Level C. Colonial G. Georgian Your Choice: S Garage Spaces: 0 Total Lot Size: 5488.82 Market Value: 388940
Screen 2 =//= Altair Realty =//= -=- Properties Inventory -=- =//= Property Listing =//= Property #: 530955 Address: 7244 Lemson Drive Alexandria, VA 22231 Condition: 3 Style: S Bedrooms: 3 Bathrooms: 1.5 Stories: 1 Year Built: 1954 Garage Spaces: 0 SqFt Lot Size: 5488.82 Market Value: $388,940.00 Press any key to continue . . .
- Close the DOS window
The Effect of Passing a Class as a Tracking Reference or as a
Handle
|
When programming in C++/CLI, most of the time, you use
classes as managed types and you pass them to functions as tracking references
or as handles. Passing a
function as a tracking reference or as a handle has the same effect as passing the argument as a
native reference: when the function ends, if it modified the argument, the object
would retain its value:
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; void Build(CCar ^ car); void Show(const CCar ^ car); |
int main() { Console::WriteLine(L"Enter Car Information"); CCar ^ vehicle = gcnew CCar; Build(vehicle); Console::WriteLine(L"\nCar Characteristics"); Show(vehicle); Console::WriteLine(); return 0; } void Build(CCar ^ car) { Console::Write(L"Enter Make: "); car->Make = Console::ReadLine(); Console::Write(L"Enter Model: "); car->Model = Console::ReadLine(); Console::Write(L"# of Doors: "); car->Doors = int::Parse(Console::ReadLine()); Console::Write(L"Year Made: "); car->Year = int::Parse(Console::ReadLine()); Console::Write(L"Enter Price: "); car->Price = double::Parse(Console::ReadLine()); } void Show(const CCar ^ car) { Console::WriteLine(L"Make: {0}", car->Make); Console::WriteLine(L"Model: {0}", car->Model); Console::WriteLine(L"Doors: {0}", car->Doors); Console::WriteLine(L"Year: {0}", car->Year); Console::WriteLine(L"Value: {0:C}", car->Price); }
Here is an example of running the program:
Enter Car Information Enter Make: Toyota Enter Model: Corolla # of Doors: 4 Year Made: 2000 Enter Price: 12650 Car Characteristics Make: Toyota Model: Corolla Doors: 4 Year: 2000 Value: $12,650.00 Press any key to continue . . .
This also means that you can pass a class type as a
tracking
reference or as a handle
with the goal of updating it. Again, this also means that you can pass
different
handles to a function and have that function return more than one value.
Remember that if a function modifies the handle, you must
not pass it as a constant.
Passing a Handle as a Reference
|
We saw that, when a function receives a handle as argument,
if it modifies the value of that handle, the argument would keep the changes
when the function terminates. You can reinforce this by passing the argument as
a tracking reference. To do this, enter the % operator between the ^ and the name of the argument. Here
is an example:
void Show(CCar ^ %car);
Notice that the space, or lack of it, between both
operators, is not important. The compiler will reconcile it when running the
application. When using the argument, you can access its member variables using
either the period or the arrow operator. Here are both functions implemented:
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; void Build(CCar ^ %car); void Show(const CCar ^ car); int main() { Console::WriteLine(L"Enter Car Information"); CCar ^ vehicle = gcnew CCar; Build(vehicle); Console::WriteLine(L"\nCar Characteristics"); Show(vehicle); Console::WriteLine(); return 0; } void Build(CCar ^ %car) { Console::Write(L"Enter Make: "); car->Make = Console::ReadLine(); Console::Write(L"Enter Model: "); car->Model = Console::ReadLine(); Console::Write(L"# of Doors: "); car->Doors = int::Parse(Console::ReadLine()); Console::Write(L"Year Made: "); car->Year = int::Parse(Console::ReadLine()); Console::Write(L"Enter Price: "); car->Price = double::Parse(Console::ReadLine()); } void Show(const CCar ^ car) { . . . }
You can also pass a handle as a native reference by using
& instead of %. This can be done as follows:
using namespace System; public value class CCar { public: String ^ Make; String ^ Model; int Doors; int Year; double Price; }; void Build(CCar ^ &car); void Show(const CCar ^ car); int main() { . . . Console::WriteLine(); return 0; } void Build(CCar ^ &car) { . . . } void Show(const CCar ^ car) { . . . }
Using the String Class
|
Returning a String
|
The string is the most regular type of value used in an
application. It can be a group of characters or symbol of any kind in any order.
To represent it, as mentioned in Lesson 4, the string is represented in the C++/CLI
language by the String class. As a managed type, a String object is
declared as a handle. This is the same basis you use to involve a String object
in a function.
As a managed class, to return a String value from a
function, when creating the function, specify that it returns a handle to
String. Here is an example:
String ^ GetPropertyAddress();
When implementing the function, in its body, do whatever you
want but the rule, as always, is that you must return a string before the
closing curly bracket. Here is an example:
using namespace System; String ^ GetPropertyAddress(); int main() { String ^ adrs = GetPropertyAddress(); Console::WriteLine(L"\nAddress: {0}", adrs); return 0; } String ^ GetPropertyAddress() { String ^ strAddress; Console::Write(L"Enter Property's Address: "); strAddress = Console::ReadLine(); return strAddress; }
Here is an example of running the program:
Enter Property's Address: 6802 Lilas Drive Address: 6802 Lilas Drive Press any key to continue . . .
A function that returns a string can take any type of
argument such as a primitive type.
Passing a String
|
A String object can be passed to a function. As a managed
type, the argument must be passed either as a tracking reference or as a handle.
To pass the argument as a handle, follow the rules we reviewed, that is, precede
the name of the argument with the ^ operator. Here is an example:
using namespace System; String ^ GetPropertyAddress(); void ShowAddress(String ^); int main() { String ^ adrs = GetPropertyAddress(); ShowAddress(adrs); return 0; } String ^ GetPropertyAddress() { String ^ strAddress; Console::Write(L"Enter Property's Address: "); strAddress = Console::ReadLine(); return strAddress; } void ShowAddress(String ^ strAdrs) { Console::WriteLine(L"\nAddress: {0}", strAdrs); }
Here is an example of running the program:
Enter Property's Address: 8804 Acacia Rd Address: 8804 Acacia Rd Press any key to continue . . .
In the same way, you can pass as many strings as you judge
necessary. Also, you can pass a mix of strings and other primitive types.
Like a variable, a function can be made a member of
a class. This allows a class to perform its own assignments and/or better
manage its behavior. These tasks cannot be handled by a regular member
variable. When a function is a member of a class, that function is
called a method.
To create a method, you start like a normal function
but you include it in the body of the class. Here is an example:
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void Build();
};
In the same way, you can add as many methods as you judge
necessary for your class. Here is an example:
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void Build();
void Show();
};
|
- To start a new project, on the main menu, click File -> New -> Project...
- On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
- In the Name box, replace the string with ElectroStore1 and click OK
- On the main menu, click Project -> Add New Item...
- To create a header file, in the Templates list, click Header File (.h)
- Set the Name to StoreItem and click Add
- Complete the file as follows:
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { private: long ItemNumber; __wchar_t ^ Category; String ^ Make; String ^ Model; double DiscountRate; double UnitPrice; }; }
- To create a source file, in the Templates list, click C++ File (.cpp)
- Set the Name to Exercise and click Add
- Complete the file as follows:
#include "StoreItem.h" using namespace System; using namespace ElectronicsStore; int main() { String ^ strTitle = L"=-= Nearson Electonics =-=\n" L"******* Store Items ******"; CStoreItem ^ item = gcnew CStoreItem; Console::WriteLine(strTitle); Console::WriteLine(); return 0; }
- Execute the application to test it. This would produce:
=-= Nearson Electonics =-= ******* Store Items ****** Press any key to continue . . .
- Close the DOS window
There are at least two techniques you can use to implement a
method. To implement a method in the class where the method is
declared, use the same techniques we used to define regular functions.
When a
method is a class' member, it has access to the member variables of the same
class; this means that you don't need to pass the variables as arguments; you can just use any of them as if it were
supplied. Here is an example:
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void Build()
{
Console::Write(L"Enter Make: ");
Make = Console::ReadLine();
Console::Write(L"Enter Model: ");
Model = Console::ReadLine();
Console::Write(L"# of Doors: ");
Doors = int::Parse(Console::ReadLine());
Console::Write(L"Year Made: ");
Year = int::Parse(Console::ReadLine());
Console::Write(L"Enter Price: ");
Price = double::Parse(Console::ReadLine());
}
void Show();
};
To call a method from a declared handle of a class, you can
use the -> operator just as you would proceed to access a member of a class.
Here is an example:
using namespace System;
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void Build()
{
Console::WriteLine(L"Enter Car Information");
Console::Write(L"Enter Make: ");
Make = Console::ReadLine();
Console::Write(L"Enter Model: ");
Model = Console::ReadLine();
Console::Write(L"# of Doors: ");
Doors = int::Parse(Console::ReadLine());
Console::Write(L"Year Made: ");
Year = int::Parse(Console::ReadLine());
Console::Write(L"Enter Price: ");
Price = double::Parse(Console::ReadLine());
}
};
int main()
{
CCar ^ vehicle = gcnew CCar;
vehicle->Build();
Console::WriteLine();
return 0;
}
|
- To implement a method locally, access the StoreItem.h file and create the
following method:
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { private: long ItemNumber; __wchar_t ^ Category; String ^ Make; String ^ Model; double DiscountRate; double UnitPrice; public: void CreateStoreItem() { Console::WriteLine(L"To create a store item, enter its information"); Console::Write(L"Item Number: "); ItemNumber = long::Parse(Console::ReadLine()); Console::WriteLine(L"Category"); Console::WriteLine(L"A - Audio Cables"); Console::WriteLine(L"B - Batteries"); Console::WriteLine(L"C - Cell Phones and Accessories"); Console::WriteLine(L"D - Bags and Cases"); Console::WriteLine(L"H - Headphones"); Console::WriteLine(L"M - Digital Cameras"); Console::WriteLine(L"O - Cables and Connectors"); Console::WriteLine(L"P - PDAs and Accessories"); Console::WriteLine(L"T - Telephones and Accessories"); Console::WriteLine(L"S - Surge Protector"); Console::Write(L"Your Choice? "); Category = __wchar_t::Parse(Console::ReadLine()); Console::Write(L"Make "); Make = Console::ReadLine(); Console::Write(L"Model: "); Model = Console::ReadLine(); Console::Write(L"Discount Applied (enter 0 if no discount): "); DiscountRate = double::Parse(Console::ReadLine()); Console::Write(L"Unit Price: "); UnitPrice = double::Parse(Console::ReadLine()); } }; }
- Save the file
Instead of using the body of a class, you can also define a
method outside of its class. To do this, start with void or the return type of
the method, followed by the name of the class, followed by the :: operator, followed by the
name of the method, followed by its parentheses, followed by the body of the
method delimited by its curly brackets. The method must have been declared in
the body of the class. Here is an example:
using namespace System; public value class CCar { private: String ^ Make; String ^ Model; int Doors; int Year; double Price; public: void Build() { Console::WriteLine(L"Enter Car Information"); Console::Write(L"Enter Make: "); Make = Console::ReadLine(); Console::Write(L"Enter Model: "); Model = Console::ReadLine(); Console::Write(L"# of Doors: "); Doors = int::Parse(Console::ReadLine()); Console::Write(L"Year Made: "); Year = int::Parse(Console::ReadLine()); Console::Write(L"Enter Price: "); Price = double::Parse(Console::ReadLine()); } void Show(); }; void CCar::Show() { Console::WriteLine(L"\nCar Characteristics"); Console::WriteLine(L"Make: {0}", Make); Console::WriteLine(L"Model: {0}", Model); Console::WriteLine(L"Doors: {0}", Doors); Console::WriteLine(L"Year: {0}", Year); Console::WriteLine(L"Value: {0:C}", Price); } int main() { CCar ^ vehicle = gcnew CCar; vehicle->Build(); vehicle->Show(); Console::WriteLine(); return 0; }
You can use a mixture of local and global method
definitions. Make sure that each method is
implemented only once, either locally, in the object, or globally, outside of
the object.
By tradition, when defined globally, the methods of a class
are implemented in the associated source file of the header file of the class.
|
- Change the StoreItem.h header file as follows:
#pragma once using namespace System; namespace ElectronicsStore { public ref class CStoreItem { private: long ItemNumber; __wchar_t ^ Category; String ^ Make; String ^ Model; double DiscountRate; double UnitPrice; public: void CreateStoreItem(); void ItemDescription(); }; }
- To create a source file, in the Templates list, click C++ File (.cpp)
- Set the Name to StoreItem and click Add
- Complete the file as follows:
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { void CStoreItem::CreateStoreItem() { Console::WriteLine(L"To create a store item, enter its information"); Console::Write(L"Item Number: "); ItemNumber = long::Parse(Console::ReadLine()); Console::WriteLine(L"Category"); Console::WriteLine(L"A - Audio Cables"); Console::WriteLine(L"B - Batteries"); Console::WriteLine(L"C - Cell Phones and Accessories"); Console::WriteLine(L"D - Bags and Cases"); Console::WriteLine(L"H - Headphones"); Console::WriteLine(L"M - Digital Cameras"); Console::WriteLine(L"O - Cables and Connectors"); Console::WriteLine(L"P - PDAs and Accessories"); Console::WriteLine(L"T - Telephones and Accessories"); Console::WriteLine(L"S - Surge Protector"); Console::Write(L"Your Choice? "); Category = __wchar_t::Parse(Console::ReadLine()); Console::Write(L"Make "); Make = Console::ReadLine(); Console::Write(L"Model: "); Model = Console::ReadLine(); Console::Write(L"Discount Applied (enter 0 if no discount): "); DiscountRate = double::Parse(Console::ReadLine()); Console::Write(L"Unit Price: "); UnitPrice = double::Parse(Console::ReadLine()); } void CStoreItem::ItemDescription() { Console::WriteLine(L"Store Item Description"); Console::WriteLine(L"Item Number: {0}", ItemNumber); Console::WriteLine(L"Category: {0}", Category); Console::WriteLine(L"Make {0}", Make); Console::WriteLine(L"Model: {0}", Model); Console::WriteLine(L"Discount Rate: {0}", DiscountRate); Console::WriteLine(L"Unit Price: {0}", UnitPrice); } }
- Access the Exercise.cpp file and change it as follows:
#include "StoreItem.h" using namespace System; using namespace ElectronicsStore; int main() { String ^ strTitle = L"=-= Nearson Electonics =-=\n" L"******* Store Items ******"; CStoreItem ^ item = gcnew CStoreItem; item->CreateStoreItem(); Console::WriteLine(); Console::WriteLine(strTitle); item->ItemDescription(); Console::WriteLine(); return 0; }
- Execute the application to test it. Here is an example:
To create a store item, enter its information Item Number: 624406 Category A - Audio Cables B - Batteries C - Cell Phones and Accessories D - Bags and Cases H - Headphones M - Digital Cameras O - Cables and Connectors P - PDAs and Accessories T - Telephones and Accessories S - Surge Protector Your Choice? M Make Canon Model: Powershot A620 Discount Applied (Enter 0 to 100, 0 if no discount): 20 Unit Price: 320.95 =-= Nearson Electonics =-= ******* Store Items ****** Store Item Description Item Number: 624406 Category: M Make Canon Model: Powershot A620 Discount Rate: 20.00 % Unit Price: $320.95 Press any key to continue . . .
- Close the DOS window
Inline Methods
|
When a method is implemented locally, that is, in the body
of a class, it is referred to as inline. To re-enforce this, you can precede its
name with the
inline keyword when declaring the method in the class. Here is an
example:
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void inline Build()
{
. . .
}
void Show();
};
If you define a method globally but you want it to be
processed as inline, precede its name with the inline keyword. Here is an
example:
public value class CCar
{
private:
String ^ Make;
String ^ Model;
int Doors;
int Year;
double Price;
public:
void inline Build()
{
. . .
}
void Show();
};
void inline CCar::Show()
{
Console::WriteLine(L"\nCar Characteristics");
Console::WriteLine(L"Make: {0}", Make);
Console::WriteLine(L"Model: {0}", Model);
Console::WriteLine(L"Doors: {0}", Doors);
Console::WriteLine(L"Year: {0}", Year);
Console::WriteLine(L"Value: {0:C}", Price);
}
You can choose which method(s) would be inline and which one(s) would
not. When implementing the method, you can precede the method with the
inline keyword. You can also omit the inline keyword in the class but use it when defining the method.
After
defining
the method of class, whether locally or globally, any method can call
another without using an access operator. This allows an
class’ methods to exchange information among themselves easily.
Furthermore, unlike regular functions where a function must be declared
prior to another function calling it, the methods of a class don't
follow that rule: one method can call another method before or after the
other has been implemented, as long as it is defined
somewhere in the program.
Class and Self Return
|
Introduction
|
When it comes to returning a class after processing it, you
have two main alternatives: you can get a class to be returned by an external
function or you can create a method that returns its own type of class. To
proceed, first declare a method by specifying its return type as the class
itself. Because a managed class can only be declared as a handle, the return
type must be specified as a handle. Here is an example:
public value class CHouse
{
public:
__wchar_t TypeOfHome;
int NumberOfBedrooms;
double NumberOfBathrooms;
Byte Stories;
int YearBuilt;
double Value;
CHouse ^ Create();
};
In the body of the method, proceed as you see fit. As done
with other functions, before the end of the method, you must remember to return
a handle to the class. Here is an example:
CHouse ^ CHouse::Create() { CHouse ^ home = gcnew CHouse; home->TypeOfHome = L's'; home->NumberOfBedrooms = 4; home->NumberOfBathrooms = 3.5; home->Stories = 2; home->YearBuilt = 2002; home->Value = 455960; return home; }
After defining a self returning method, you can call it like
you would any normal method. Here is an example:
using namespace System;
public value class CHouse
{
public:
__wchar_t TypeOfHome;
int NumberOfBedrooms;
double NumberOfBathrooms;
Byte Stories;
int YearBuilt;
double Value;
CHouse ^ Create();
void Show();
};
int main()
{
CHouse ^ House2002 = gcnew CHouse;
CHouse ^ Property = House2002->Create();
Property->Show();
Console::WriteLine();
return 0;
}
CHouse ^ CHouse::Create()
{
CHouse ^ home = gcnew CHouse;
home->TypeOfHome = L's';
home->NumberOfBedrooms = 4;
home->NumberOfBathrooms = 3.5;
home->Stories = 2;
home->YearBuilt = 2002;
home->Value = 455960;
return home;
}
C++ proposes an alternative to returning a class from one
of its methods. Instead of explicitly declaring a variable when
implementing a method that returns the same class, the compiler simply needs
to know what object you want to return: the object that called the method or a
newly declared one. If you want to return the same object, you can use a special
pointer called this.
As its name implies, the this pointer is a self referencing object, which means it allows you to designate the object that is making the call as the same object you are referring to. Using the this pointer is a technique that allows you to perform any necessary operation on an object without the help of an external function and returning the same object.
Suppose you want to transform the Create() method of the CHouse class above so it would return the same variable that calls it. Because the method will return the same object, you don't need to declare a local variable to hold the changed variable. Since the member variables of the class will be modified, the method cannot be declared as a constant.
As its name implies, the this pointer is a self referencing object, which means it allows you to designate the object that is making the call as the same object you are referring to. Using the this pointer is a technique that allows you to perform any necessary operation on an object without the help of an external function and returning the same object.
Suppose you want to transform the Create() method of the CHouse class above so it would return the same variable that calls it. Because the method will return the same object, you don't need to declare a local variable to hold the changed variable. Since the member variables of the class will be modified, the method cannot be declared as a constant.
When implementing this method, the values of the variables
will certainly be modified to implement whatever behavior you want. To return
the same object, the this object must be called as a pointer, with *this.
This would be done as follows:
CHouse ^ CHouse::Create()
{
return *this;
}
One way you can use a method that self-returns its class is
to initialize its member variables. Since the method returns its class, you can
therefore return a pointer to this. Here is an example:
using namespace System;
public value class CHouse
{
public:
__wchar_t TypeOfHome;
int NumberOfBedrooms;
double NumberOfBathrooms;
Byte Stories;
bool HasGarage;
int YearBuilt;
double Value;
CHouse ^ Create();
void Show();
};
int main()
{
CHouse ^ House2002 = gcnew CHouse;
CHouse ^ Property = House2002->Create();
Property->Show();
Console::WriteLine();
return 0;
}
CHouse ^ CHouse::Create()
{
TypeOfHome = L'C';
NumberOfBedrooms = 1;
NumberOfBathrooms = 1.0;
Stories = 1;
HasGarage = false;
YearBuilt = 1960;
Value = 100000;
return *this;
}
void CHouse::Show()
{
. . .
}
Instead of returning a handle, since the method that returns the this pointer
returns it as a pointer, you can make it return a tracking reference. Here is an
example:
CHouse % CHouse::Create()
{
TypeOfHome = L'C';
NumberOfBedrooms = 1;
NumberOfBathrooms = 1.0;
Stories = 1;
HasGarage = false;
YearBuilt = 1960;
Value = 100000;
return *this;
}
This version of the method would produce the same effect as
the previous one.
|
- Access the StoreItem.cpp source file
- To use the this pointer, change the members of the class as follows:
#include "StoreItem.h" using namespace System; namespace ElectronicsStore { void CStoreItem::CreateStoreItem() { Console::WriteLine(L"To create a store item, enter its information"); Console::Write(L"Item Number: "); this->ItemNumber = long::Parse(Console::ReadLine()); Console::WriteLine(L"Category"); Console::WriteLine(L"A - Audio Cables"); Console::WriteLine(L"B - Batteries"); Console::WriteLine(L"C - Cell Phones and Accessories"); Console::WriteLine(L"D - Bags and Cases"); Console::WriteLine(L"H - Headphones"); Console::WriteLine(L"M - Digital Cameras"); Console::WriteLine(L"O - Cables and Connectors"); Console::WriteLine(L"P - PDAs and Accessories"); Console::WriteLine(L"T - Telephones and Accessories"); Console::WriteLine(L"S - Surge Protector"); Console::Write(L"Your Choice? "); this->Category = __wchar_t::Parse(Console::ReadLine()); Console::Write(L"Make "); this->Make = Console::ReadLine(); Console::Write(L"Model: "); this->Model = Console::ReadLine(); Console::Write(L"Discount Applied (Enter 0 to 100, 0 if no discount): "); this->DiscountRate = double::Parse(Console::ReadLine()); Console::Write(L"Unit Price: "); this->UnitPrice = double::Parse(Console::ReadLine()); } void CStoreItem::ItemDescription() { Console::WriteLine(L"Store Item Description"); Console::WriteLine(L"Item Number: {0}", this->ItemNumber); Console::WriteLine(L"Category: {0}", this->Category); Console::WriteLine(L"Make {0}", this->Make); Console::WriteLine(L"Model: {0}", this->Model); Console::WriteLine(L"Discount Rate: {0:P}", this->DiscountRate / 100); Console::WriteLine(L"Unit Price: {0:C}", this->UnitPrice); } }
- Execute the application to test it
- Close the DOS window
No comments:
Post a Comment