Home

Passing Arguments by Reference

 

Passing by Native Reference

When you declare a variable in a program, the compiler reserves an amount of space for that variable. If you need to use that variable somewhere in your program, you call it and make use of its value. There are two major issues related to a variable: its value and its location in the memory. The location of a variable in memory is referred to as its address.

If you supply the argument using its name, as we have done so far, the compiler only makes a copy of the argumentís value and gives it to the calling function. Although the calling function receives the argumentís value and can use in any way, it cannot (permanently) alter it. C++ allows a calling function to modify the value of a passed argument if you find it necessary. If you want the calling function to modify the value of a supplied argument and return the modified value, you should pass the argument using its reference.

To pass an argument as a reference, when declaring the function, precede the argument name with an ampersand ď&Ē. You can pass one or more arguments as reference in the program or pass all arguments as reference. The decision as to which argument(s) should be passed by value or by reference is based on whether or not you want the called function to modify the argument and permanently change its value.

Here are examples of passing some arguments by reference:

void Area(double &Side); // The argument is passed by reference
bool Decision(char &Answer, int Age); // One argument is passed by reference
// All arguments are passed by reference
float Purchase(float &DiscountPrice, float &NewDiscount, char &Commission);

Once again, the signature of the function is important when declaring the function. The compiler would not care much about the name of an argument. Therefore, the above functions can be declared as follows:

void Area(double &); 
bool Decision(char &, int );
float Purchase(float &, float &, char &);

You add the ampersand when declaring a function and/or when defining it. When calling the function, supply only the name of the referenced argument(s). The above would be called with:

Area(Side);
Decision(Answer, Age);
Purchase(DiscountPrice, NewDiscount, Commission);

You will usually need to know what happens to the value passed to a calling function because the rest of the program may depend on it.

Passing by Constant Reference

We have seen that passing an argument as a reference allows the compiler to retrieve the real value of the argument at its location rather than sending a request for a value of the variable. This speeds up the execution of the program. Also, when passing an argument as a constant, the compiler will make sure that the value of the passed argument is not modified.

If you pass an argument as reference, the compiler would access the argument from its location. The called function can modify the value of the argument. The advantage is that code execution is faster because the argument gives access to its address. The disadvantage could be that if the calling function modifies the value of the argument, when the function exits, the value of the argument would have (permanently) changed and the original value would be lost (actually, this can be an advantage as we have learned). If you do not want the value of the passed argument to be modified, you should pass the argument as a constant reference. When doing this, the compiler would access the argument at its location (or address) but it would make sure that the value of the argument stays intact.

To pass an argument as a constant reference, when declaring the function and when implementing it, type the const keyword, followed by the argument data type, followed by the ampersand operator "&", followed by a name for the argument. When declaring the function, the name of the argument is optional. Here is a function that receives an argument as a constant reference:

double CalculateDiscount(const double &Original, double Rate)
{
    return Original * Rate / 100;
}

You can mix arguments passed by value, those passed as reference, those passed by constant, and those passed by constant references. You will decide, based on your intentions, to apply whatever technique suits your scenario.

The following program illustrates the use of various techniques of passing arguments:

using namespace System;

double CalculateDiscount(const double &MarkedPrice, double = 20);
double PriceAfterDiscount(const double, const double);
double CalculateTaxAmount(const double &, double);
double CalculateNetPrice(const double &, const double &);
void DisplayResult(double, double, double, double, double);

void RequestOriginalPrice(double &Price)
{
    Console::Write("Enter the original price: $");
    Price = double::Parse(Console::ReadLine());
}

void RequestDiscountRate(double &Discount)
{
    Console::Write("Enter discount rate(0.00 to 100.00): ");
    Discount = double::Parse(Console::ReadLine());
}

void RequestTaxRate(double& Tax)
{
    Console::Write("Enter the tax rate(0.00 to 100.00): ");
    Tax = double::Parse(Console::ReadLine());
}

int main()
{
    double OriginalPrice, DiscountRate, AfterDiscount, TaxRate;
    double DiscountAmount, TaxAmount, NetPrice;

    RequestOriginalPrice(OriginalPrice);
    RequestDiscountRate(DiscountRate);
    RequestTaxRate(TaxRate);

    DiscountAmount = CalculateDiscount(OriginalPrice, DiscountRate);
    AfterDiscount  = PriceAfterDiscount(OriginalPrice, DiscountAmount);
    TaxAmount      = CalculateTaxAmount(AfterDiscount, TaxRate);
    NetPrice       = CalculateNetPrice(AfterDiscount, TaxAmount);

    DisplayResult(OriginalPrice, DiscountAmount,
                  AfterDiscount, TaxAmount, NetPrice);
    
    return 0;
}

double CalculateDiscount(const double &Original, double Rate)
{
    return Original * Rate / 100;
}

double PriceAfterDiscount(const double Original, const double Discount)
{
    return Original - Discount;
}

double CalculateTaxAmount(const double &Discount, double Rate)
{
    return Discount * Rate / 100;
}

double CalculateNetPrice(const double &Discount, const double &TaxAmt)
{
    return Discount + TaxAmt;
}

void DisplayResult(const double OrigPrice, const double DiscAmt,
                   const double Discount, const double TaxAmt,
                   const double FinalPrice)
{
    Console::WriteLine("\nReceipt");
    Console::WriteLine("Original Price:  {0:C}", OrigPrice);
    Console::WriteLine("Discount Amount: {0:C}", DiscAmt);
    Console::WriteLine("After Discount:  {0:C}", Discount);
    Console::WriteLine("Tax Amount:      {0:C}", TaxAmt);
    Console::WriteLine("Net Price:       {0:C}", FinalPrice);
}

Here is an example of running the program:

Enter the original price: $885.95
Enter discount rate(0.00 to 100.00): 40
Enter the tax rate(0.00 to 100.00): 5.75

Receipt
Original Price:  $885.95
Discount Amount: $354.38
After Discount:  $531.57
Tax Amount:      $30.57
Net Price:       $562.14
Press any key to continue . . .

Passing by Tracking Reference

When programming in C++/CLI rather than C++, a tracking reference may be your most regular choice if you want to pass an argument by reference. This is because, as we will learn with classes, a managed object cannot directly use a C++ regular reference. Fortunately, as done for a native reference, you can pass an argument using a tracking reference. To do this, precede the name of the argument with the % operator.

Everything considered, you pass an argument by tracking reference exactly as you would a native reference: the rules are the same. Here are example:

using namespace System;

void GetHourlySalary(double % salary)
{
	Console::Write(L"Hourly Salary: ");
	salary = double::Parse(Console::ReadLine());
}

void GetWeeklyHours(double %);
void CalculateWeeklySalary(double %, double, double);
void ShowPaycheck(double hourly, double hours, double weekly);

int main()
{
        double HourlySalary, WeeklyHours, WeeklySalary;

	Console::WriteLine(L"Payroll Preparation");
	Console::WriteLine(L"Enter the following information");
        GetHourlySalary(HourlySalary);
	GetWeeklyHours(WeeklyHours);
	CalculateWeeklySalary(WeeklySalary, HourlySalary, WeeklyHours);
    
	Console::WriteLine();

	ShowPaycheck(HourlySalary, WeeklyHours, WeeklySalary);
        return 0;
}

void GetWeeklyHours(double % hours)
{
	Console::Write(L"Weekly Hours:  ");
	hours = double::Parse(Console::ReadLine());
}

void CalculateWeeklySalary(double % weekly, double hourly, double hours)
{
	weekly = hourly * hours;
}

void ShowPaycheck(double hourly, double hours, double weekly)
{
	Console::WriteLine(L"Employee Paycheck");
	Console::WriteLine(L"Hourly Salary: {0:C}", hourly);
	Console::WriteLine(L"Weekly Hours:  {0:F}", hours);
	Console::WriteLine(L"Weekly Salary: {0:C}", weekly);
}

This would produce:

Payroll Preparation
Enter the following information
Hourly Salary: 18.42
Weekly Hours:  42.50

Employee Paycheck
Hourly Salary: $18.42
Weekly Hours:  42.50
Weekly Salary: $782.85
Press any key to continue . . .

As mentioned for native references, when an argument is passed by tracking reference, the argument is modified by the function. That is, when the function closes, the parameter passed by tracking reference holds the value as it was changed in the function, if it was changed.

Also, as mentioned for the native references, the ability to pass various parameters by tracking references allows a single function to return more than one value. Here is an example:

using namespace System;

void PreparePayroll(double %, double %);

void CalculateWeeklySalary(double %, double, double);
void ShowPaycheck(double hourly, double hours, double weekly);

int main()
{
        double HourlySalary, WeeklyHours, WeeklySalary;

	Console::WriteLine(L"Payroll Preparation");
	Console::WriteLine(L"Enter the following information");
        PreparePayroll(HourlySalary, WeeklyHours);
	CalculateWeeklySalary(WeeklySalary, HourlySalary, WeeklyHours);
    
	Console::WriteLine();

	ShowPaycheck(HourlySalary, WeeklyHours, WeeklySalary);
        return 0;
}

void PreparePayroll(double % salary, double % hours)
{
	Console::Write(L"Hourly Salary: ");
	salary = double::Parse(Console::ReadLine());

	Console::Write(L"Weekly Hours:  ");
	hours = double::Parse(Console::ReadLine());
}

void CalculateWeeklySalary(double % weekly,
			   const double hourly,
			   const double hours)
{
	weekly = hourly * hours;
}

void ShowPaycheck(double hourly, double hours, double weekly)
{
	Console::WriteLine(L"Employee Paycheck");
	Console::WriteLine(L"Hourly Salary: {0:C}", hourly);
	Console::WriteLine(L"Weekly Hours:  {0:F}", hours);
	Console::WriteLine(L"Weekly Salary: {0:C}", weekly);
}

Just as done for a native reference, you can pass a tracking reference by constant. The main rule is to remember, then, is that the called function cannot modify the value of the argument. Here are examples:

using namespace System;

void PreparePayroll(double %, double %);

void CalculateWeeklySalary(double %, double, double);
void ShowPaycheck(const double %, const double %, const double %);

int main()
{
        double HourlySalary, WeeklyHours, WeeklySalary;

	Console::WriteLine(L"Payroll Preparation");
	Console::WriteLine(L"Enter the following information");
        PreparePayroll(HourlySalary, WeeklyHours);
	CalculateWeeklySalary(WeeklySalary, HourlySalary, WeeklyHours);
    
	Console::WriteLine();

	ShowPaycheck(HourlySalary, WeeklyHours, WeeklySalary);
        return 0;
}

void PreparePayroll(double % salary, double % hours)
{
	Console::Write(L"Hourly Salary: ");
	salary = double::Parse(Console::ReadLine());

	Console::Write(L"Weekly Hours:  ");
	hours = double::Parse(Console::ReadLine());
}

void CalculateWeeklySalary(double % weekly,
			   const double hourly, const double hours)
{
	weekly = hourly * hours;
}

void ShowPaycheck(const double % hourly,
		  const double % hours,
		  const double % weekly)
{
	Console::WriteLine(L"Employee Paycheck");
	Console::WriteLine(L"Hourly Salary: {0:C}", hourly);
	Console::WriteLine(L"Weekly Hours:  {0:F}", hours);
	Console::WriteLine(L"Weekly Salary: {0:C}", weekly);
}
 

Previous Copyright © 2006 FunctionX, Inc. Next