Home

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 LearningPractical Learning: Passing a Handle

  1. 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;
    }
  2. 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 . . .
  3. 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);
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)
{
    . . .
}
 

Previous Copyright © 2006 FunctionX, Inc. Next