Introduction to Classes and Functions
Introduction to Classes and Functions
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 . . .
Practical Learning: Introducing Data Reading |
#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; }; }
#pragma once #include "Property.h" using namespace System; namespace RealEstate { public ref class CHouse : public CProperty { public: Byte Stories; int Condition; unsigned NumberOfGarageSpaces; }; }
#pragma once #include "House.h" using namespace System; namespace RealEstate { public ref class CSingleFamily : public CHouse { public: __wchar_t Style; double LotSizeInSqFt; }; }
#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; }
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.
Practical Learning: Returning a Handle |
#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; }
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.
Practical Learning: Passing a Handle |
#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; }
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 . . .
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:
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.
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) { . . . }
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.
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(); };
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; }
|