Broad Network


Understanding C++ Reference

Some Features of C++ Entities – Part 9

Forward: In this part of the series, I explain C++ reference in detail, the way it was meant to be.

By: Chrysanthus Date Published: 25 Sep 2012

Introduction

This is part 9 of my series, Some Features of C++ Entities. In this part of the series, I explain C++ reference in detail, the way it was meant to be. C++ is a superset of C. When C come up, you had the reference and its reference operator & and not the pointer and its dereference operator, *. In this part of the series, I explain C++ rerference and its operator only, in details. In a later part of the series, I will compare the C++ reference and the C++ pointer. You should try the code segments in this part of the series, in a main method.

You should be reading the tutorials of this series in the order given. You also should have read the other C++ series before this one (check the C++ course link below).

C++ Reference Basics
Consider the following code segment:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';
        cout << &herInt << '\n';


& is known as the reference operator. For my computer, the output of the above code segment is:

5
5
0x22ff48

In your computer, the third line will begin with 0x and may continue with different text. The third line is actually a memory address in hexadecimal number form.

In the code segment, the value 5 is assigned to the identifier, hisInt, in the first line. In the second code segment line, the identifier, hisInt is assigned in a special way to the new identifier, herInt. In the same statement the operator, & acts on the new identifier, herInt. The operator acts to determine the address of the region (area) in memory (of fundamental object) that has the content of the new identifier, herInt. The preceding specifier, int, indicates that the identifier, herInt, holds (or should hold) an int (integer).

Now, something like, &herInt, will always be seen in C++ coding. &herInt and herInt are not the same entity. herInt is the identifier of a region in memory, while the operator, & acts on herInt to produce the start memory address of the region (the region of an int, no matter the value of the int, is typically 4 bytes long). The start memory address of a region is considered as the address of the region.

In the second statement of the code segment, there are actually two operators. A C++ statement can have more than one operator (two, three, etc.). In the statement, the & operator acts first before the = operator. Still in the second line, the address produced cannot be accessed (read) by the programmer.

In the code segment, at the second line (second statement), the value (content) of hisInt and herInt are the same. In the third line, the value of hisInt is displayed. In the fourth line, the value of herInt is displayed. In the fifth line, the expression, &herInt, works out the address of hetInt and the cout object displays it. In the fifth line, the address determined (worked out) is still not really stored in memory to be accessible by the programmer.

In the second statement (line) in the code, the expression, &herInt, also determines the address of the region identified by herInt. In the whole code, this particular address is determined in two places.

So, if & precedes an identifier, it produces the address of the identifier. Its presence does not disturbed the fundamental meaning of the statement or complete expression in which it finds itself. Depending on the circumstances, the address may or may not be accessible by the programmer. In the above code, the address produced (twice) is not accessible by the programmer. In the second statement, the address is clearly not accessible by the programmer. In the last statement, the addresss is displayed but not accessed directly by the programmer. Here, the address is used by the programmer but not really accessed (read to an identifier) by the programmer.

In the second statement, the preceding int specifier indicates that herInt holds or is to hold an integer, just as in the first statement the preceding int specifier indicates that hisInt holds or is to hold an integer. So, having the & operator in the left operand of an assignment operator, is OK.

Position of &
& is an operator. So, it does not matter whether it is closer to the identifier or closer to the specifier (e.g. int) or some other item. So the following two expressions are the same:

        int &herInt

        int& herInt

For the same reason, the following expressions are the same:

        cout << &herInt
        cout <<& herInt

So, the following code segment is the same as the one above:

        int hisInt = 5;
        int& herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';
        cout <<& herInt << '\n';

Identifiers and Address
Each unique identifier has a unique address. The following code segment illustrates this:

        int yourInt;
        int hisInt = 5;
        int herInt = 6;
        cout << &yourInt << '\n';
        cout << &hisInt << '\n';
        cout << &herInt << '\n';

For my computer, I had the following output:

0x22ff4c
0x22ff48
0x22ff44

Your own computer output would be different but the preceding 0x will be there for each address.

Two Identifiers with the same Address
The vary first code segment above is re-typed here, that is:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';
        cout << &herInt << '\n';

In the second statement the two identifiers (names) have the same address. The identifier, herInt is of a declaration. It is on the left of the assignment operator. Here the assignment operator behaves in an overloaded fashion; it does not behave in the normal fashion. It actually assigns but the address of the ordinary right (assignment) operand identifier which does not have (not preceded by) &, to the left operand identifier that is preceded by &. The following code segment shows that the two identifiers have the same address:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';
        cout << &hisInt << '\n';
        cout << &herInt << '\n';

If you have tried the code, you would notice that the address is the same for the hisInt and herInt identifiers.

So, the second statement with the special left assignment operand enables two identifiers to have the same address. In other words, the two identifiers identifier the same memory region. This also shows us one way to make two identifiers identify the same memory region; that is, it shows us one way to make two identifiers identify the same value (a value is kept in a memory region).

Note: the following code segment is OK:

        int hisInt;
        int &herInt = hisInt;
        hisInt = 5;
        cout << hisInt << '\n';
        cout << herInt << '\n';
        cout << &hisInt << '\n';
        cout << &herInt << '\n';

The first statement declares an ordinary int identifier without initialization (i.e. an identified region is declared but with no value). The second statement declares a new identifier and makes the two identifiers have the same address. The third statement gives value to the first identifier and automatically to the new identifier, since they identify the same region. The rest of the statements have been explain before.

Behavior of the Assignment Operator
The focus here is the second statement above. Because of the special left assignment operand (&herInt), the assignement operator behaves in a special way: it would only assign the address of an ordinary identifier on its right to the identifier preceded by &, on its left. So, the following statement will not work:

        int &herInt = 2;

Here, on its right you have but a value and not an ordinary identifier. The following statements work because on its right you have an ordinary identifier:

        int hisInt;
        int &herInt = hisInt;

Same Address and same Value
The famous second statement above shows us how to make two identifiers have the same address to identify the same memory region and to hold the same value. The statement is,

        int &herInt = hisInt;

Note, "&herInt" is the first (left) operand of the assignment operator.

Other Fundamental Object Types
All the above principles apply to other fundamental object types like float and bool. So, if you replace all the above int specifiers with float, all the code segments will still work.

Reference and Value of Identifier
The reference is obtained with the reference operator, &, and the reference is actually the address of a region in memory identified, by an identifier. If you want the value of the region, use the identifier. The following code segment illustrates this:

        int hisInt = 5;
        int &herInt = hisInt;
        cout << hisInt << '\n';
        cout << herInt << '\n';

Here, the identifiers hisInt and herInt hold the same value for the same region. So, each of them, without, &, displays the value 5.

The Reference Operator in a Function Parameter
The parameter of a function can be a reference (address of an object). The following code illustrates this:

#include <iostream>
using namespace std;

    int aFn(int &no)
        {
            cout << no; cout << "\n";

            no = 77;
            
        }

    int main()
        {
            int theInt = 88;
            aFn(theInt);
    
            cout << theInt;
    
            return 0;
        }

As the program starts, 88 is assigned to the object whose identifier is theInt, in main. The next statement in the main function calls the function, aFn, passing the identifier of the object whose value is 88 as argument. The parameter of the called function is “int &no”. Immediately the called function starts executing, the parameter address becomes equivalent to &theInt, which is the address of the object declared in the first statement of the main function. So immediately the execution of the called function starts, &no and &theInt are the same address to one object; that is, no and theInt are identifying the same object.

The first statement in the called function displays the value of no which is the same as the value of theInt. The second statement in the called function assigns a new value to no, automatically assigning the new value to theInt, because both identifiers identify the same object. The called function does not have a return statement even though its definition begins with a return type; that is acceptable in C++; that is not part of the topic here; it is for those who may be inquisitive.

Back in the main function: The called function is called by the second statement in the main function. The called function executes before the next (third) statement in the main function is executed. I did not assign any return value of the called function to any object (identifier) in the main function. I could not do this because the called function did not return anything (had no return statement; not part of this topic though).

The third statement in the main function displays the value of theInt, which is the same as the new value for no in the called function.

Note: when passing by reference, the parameter (in called function) is the address of an object (identifier) but the argument (in calling function) is an identifier and not the address of the object (value) sent. In the above program, immediately the called function starts executing, the following un-typed statement goes into effect:

    int &no = theInt;

This is similar to the famous second statement above.

Note: in the parameter, it does not matter whether & is closer to no or int.

Reference in Function Returned Type Specifier
Consider the following program that works:

#include <iostream>
using namespace std;

    int &aFn()
        {
          int hisInt;
          int &herInt = hisInt;
          hisInt = 5;
          return herInt;
        }

    int main()
        {
            int ident = aFn();
            cout << ident;  

            return 0;
        }

In this code we have a reference function returned type. Note the position of the & operator in the function declaration. The return type of the function has to be of the same type as the item returned. What is returned is the identifier of a reference; that is, the (new) identifier preceded by & in the function body. The returned identifier has the value, 5. Returning an actual value such as 5 would not work. What is returned is received in main by an ordinary identifier (of the same type).

Note: it does not matter, whether & is closer to int or aFn() at the beginning of the function declaration.

Constant Referenced Value
You can make the referenced value constant. Consider the following initialization:

          int hisInt = 5;
          const int &herInt = hisInt;

Remember, herInt and hisInt have the same address and so hold the same value. Note the position of the specifier, const, in the statement. With this, you cannot change the value of herInt using the identifier, herInt, by assigning in a different statement. You can however change it using the identifier, hisInt, by assigning in a different statement. So, the value is constant with respect to the reference identifier.

In the following code, the third line will not work because an attempt is made to change the value of herInt using herInt:

            int hisInt = 5;
            const int &herInt = hisInt;

            herInt = 6;

That is it for this part of the series. We stop here and continue in the next part.

Chrys

Related Courses

C++ Course
Relational Database and Sybase
Windows User Interface
Computer Programmer – A Jack of all Trade – Poem
NEXT

Comments

Become the Writer's Fan
Send the Writer a Message