Pointers and Classes

Native References

As done for variables of primitive types, you can create a reference to a class using a declared variable. The same rule applies: the object that is used as a reference must have been previously initialized.

Practical LearningPractical Learning: Introducing Pointers and Classes

  1. To start a new program, launch Microsoft Visual C++ 2008
  2. On the main menu, click File -> New -> Project...
  3. On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
  4. In the Name box, replace the string with RealEstate5 and click OK
  5. To create a source file, on the main menu, click Project -> Add New Item...
  6. In the Templates list, click Source File (.cpp)
  7. In the New box, type Exercise and click Add
  8. In the empty file, type:
     
    using namespace System;
    
    public value class CProperty
    {
    public:
        __wchar_t TypeOfHome;
        int       Bedrooms;
        float     Bathrooms;
        Byte      Stories;
        int       YearBuilt;
        double    Value;
    };
    
    int main()
    {
        CProperty townhouse;
    
        townhouse.YearBuilt = 1986;
        townhouse.Bathrooms = 1.5f;
        townhouse.Stories = 3;
        townhouse.Value = 348255;
        townhouse.Bedrooms = 3;
        townhouse.TypeOfHome = L'T';
    
        CProperty &townhome = townhouse;
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        Console::Write("Type of Home:        ");
        Console::WriteLine(townhome.TypeOfHome);
        Console::Write("Number of Bedrooms:  ");
        Console::WriteLine(townhome.Bedrooms);
        Console::Write("Number of Bathrooms: ");
        Console::WriteLine(townhome.Bathrooms);
        Console::Write("Number of Stories:   ");
        Console::WriteLine(townhome.Stories);
        Console::Write("Year Built:          ");
        Console::WriteLine(townhome.YearBuilt);
        Console::Write("Monetary Value:      ");
        Console::WriteLine(townhome.Value);
    
        Console::WriteLine();
        return 0;
    }
  9. To execute the application, on the main menu, click Debug -> Start Without Debugging
  10. Click Yes
    =//= Altair Realty =//=
    -=- Properties Inventory -=-
    Type of Home:        T
    Number of Bedrooms:  3
    Number of Bathrooms: 1.5
    Number of Stories:   3
    Year Built:          1986
    Monetary Value:      348255
    
    Press any key to continue . . .
  11. After viewing the file, close the DOS window

Introduction to Pointers to Classes

As done with variables of the regular data types, you can declare a pointer to a class. Here is an example:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *square;

    return 0;
}

After declaring the pointer, you should let the compiler know what variable the pointer is pointing to. This can easily be done by assigning the address of an existing object as follows:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare sqr;
    CSquare *square = &sqr;

    Console::WriteLine();
    return 0;
}

Practical LearningPractical Learning: Introducing Pointers to Classes

  1. To declare a pointer to class, change the main() function as follows:
    using namespace System;
    
    public value class CProperty
    {
    public:
        __wchar_t TypeOfHome;
        int       Bedrooms;
        float     Bathrooms;
        Byte      Stories;
        int       YearBuilt;
        double    Value;
    };
    
    int main()
    {
        CProperty  condominium;
        CProperty *apartment = &condominium;
    
        Console::WriteLine();
        return 0;
    }
  2. Save the file

Accessing the Members of a Pointer to a Class

After declaring a pointer to a class, to use it, you can access one, a few, or all of its members. You have a choice between two operators: the period and the arrow.

We saw that the asterisk "*" on the left side of a pointer represented the value of the variable. In the case of a class, when writing *sqr, this represents a CSquare object and it holds the values of the object to which it would have been initialized. To access its members, yon can use the period operator that is used to access the values of an object. Because the period has a higher precedence than the asterisk, you must include the object and its asterisk between parentheses. Here is an example:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare sqr;
    sqr.Side = 24.48;

    CSquare *square = &sqr;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine((*square).Side);

    Console::WriteLine();
    return 0;
}

As an alternative, you can access the values using the pointer to the class. In this case, you would use the name of the pointer and the arrow operator. Here are examples:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare sqr;
    sqr.Side = 24.48;

    CSquare *square = &sqr;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine(square->Side);

    Console::WriteLine();
    return 0;
}

Both notations produce the same result:

Square Characteristics
Side: 24.48

Press any key to continue . . .

Practical LearningPractical Learning: Accessing the Members of a Pointer to a Class

  1. To access the members of a pointer to class, change the main() function as follows:
    using namespace System;
    
    public value class CProperty
    {
    public:
        __wchar_t TypeOfHome;
        int       Bedrooms;
        float     Bathrooms;
        Byte      Stories;
        int       YearBuilt;
        double    Value;
    };
    
    int main()
    {
        CProperty  apartment;
        CProperty *condominium = &apartment;
    
        condominium->YearBuilt = 1986;
        condominium->Bathrooms = 1.5f;
        condominium->Stories = 3;
        condominium->Value = 348255;
        condominium->Bedrooms = 3;
        condominium->TypeOfHome = L'T';
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        Console::Write("Type of Home:        ");
        Console::WriteLine(condominium->TypeOfHome);
        Console::Write("Number of Bedrooms:  ");
        Console::WriteLine(condominium->Bedrooms);
        Console::Write("Number of Bathrooms: ");
        Console::WriteLine(condominium->Bathrooms);
        Console::Write("Number of Stories:   ");
        Console::WriteLine(condominium->Stories);
        Console::Write("Year Built:          ");
        Console::WriteLine(condominium->YearBuilt);
        Console::Write("Monetary Value:      ");
        Console::WriteLine(condominium->Value);
    
        Console::WriteLine();
        return 0;
    }
  2. Execute the application to see the result

Allocating Memory on the Native Heap

Using a pointer allows you to use memory only as needed. This is done by using the asterisk * and the new operators. The syntax of declaring a pointer to a class is:

ClassName* VariableName = new ClassName;

The ClassName is the class whose variable you want to declare. It could be in the program or one that shipped with the compiler. Once again, the asterisk lets the compiler know that the object is declared as a pointer. The variable name follows the same rules we have applied to other variables so far.

After declaring the pointer, you can access each of its members and assign it an appropriate value. Here are examples:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *square = new CSquare;
    square->Side = 24.48;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine(square->Side);

    Console::WriteLine();
    return 0;
}

Practical LearningPractical Learning: Allocating Memory on the Native Heap

  1. To allocate memory on the heap, change the main() function as follows:
    using namespace System;
    
    public value class CProperty
    {
    public:
        __wchar_t TypeOfHome;
        int       Bedrooms;
        float     Bathrooms;
        Byte      Stories;
        int       YearBuilt;
        double    Value;
    };
    
    int main()
    {
        CProperty *condominium = new CProperty;
    
        condominium->YearBuilt = 2000;
        condominium->Bathrooms = 1.0f;
        condominium->Stories = 1;
        condominium->Value = 224825;
        condominium->Bedrooms = 1;
        condominium->TypeOfHome = L'C';
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        Console::Write("Type of Home:        ");
        Console::WriteLine(condominium->TypeOfHome);
        Console::Write("Number of Bedrooms:  ");
        Console::WriteLine(condominium->Bedrooms);
        Console::Write("Number of Bathrooms: ");
        Console::WriteLine(condominium->Bathrooms);
        Console::Write("Number of Stories:   ");
        Console::WriteLine(condominium->Stories);
        Console::Write("Year Built:          ");
        Console::WriteLine(condominium->YearBuilt);
        Console::Write("Monetary Value:      ");
        Console::WriteLine(condominium->Value);
    
        Console::WriteLine();
        return 0;
    }
  2. Execute the application to see the result
  3. Close the DOS window

De-Allocating Memory from the Native Heap

After using a variable that was declared using the new operator, you can reclaim the memory space it was using. This is done with the delete operator.

Here is an example:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *square = new CSquare;
    square->Side = 24.48;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine(square->Side);

    delete square;
    Console::WriteLine();
    return 0;
}

Practical LearningPractical Learning: De-Allocating Memory from the Native Heap

  1. To de-allocate memory, change the main() function as follows:
    using namespace System;
    
    public value class CProperty
    {
    public:
        __wchar_t TypeOfHome;
        int       Bedrooms;
        float     Bathrooms;
        Byte      Stories;
        int       YearBuilt;
        double    Value;
    };
    
    int main()
    {
        CProperty *condominium = new CProperty;
    
        . . .
    
        delete condominium;
        Console::WriteLine();
        return 0;
    }
  2. Execute the application to see the result
  3. Close the DOS window

Classes and Pointers to Pointers

 

Declaring a Pointer to Pointer

In Lesson 3, we saw how to declare a pointer to a pointer to a primitive type. In the same way, you can declare a pointer to a pointer to a class. Here is an example:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare **square;

    Console::WriteLine();
    return 0;
}

One way you can use such a variable is to initialize it with a reference to a pointer of the same type. This could be done as follows:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *sqr = new CSquare;
    CSquare **square;

    square = &sqr;

    Console::WriteLine();
    return 0;
}

Remember that, for a double-pointer to a class, such as **square, the expression *square is a pointer to the class. This means that you can use the single asterisk to access the (public) members of the object. To do this, you can use the arrow -> operator. Because the -> operator has higher precedence than the asterisk, you must isolate *square by including it in parentheses. This would be done as follows:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *sqr = new CSquare;
    CSquare **square;

    square = &sqr;

    (*square)->Side = 24.48;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine((*square)->Side);

    delete sqr;

    Console::WriteLine();
    return 0;
}

You may remember that the name of a pointer variable preceded with the asterisk represents the value held by the variable. When applied to a class, for a single pointer, the name preceded with * is the value of the variable. For a double-pointer, the name preceded with two asterisks is the value held by the pointer to pointer. This allows you to access the members of the class using the period operator. The above program can be written as:

using namespace System;

public value struct CSquare
{
    double Side;
};

int main()
{
    CSquare *sqr = new CSquare;
    CSquare **square;

    square = &sqr;

    (**square).Side = 24.48;

    Console::WriteLine("Square Characteristics");
    Console::Write("Side: ");
    Console::WriteLine((*square)->Side);

    delete sqr;

    Console::WriteLine();
    return 0;
}

Just as demonstrated in Lesson 3, after initializing a pointer, if you change the value of the variable it points to, the pointer would be updated. If the variable was declared as a pointer to pointer and if you change either the pointer it points to, the pointer to pointer would be updated.

Handle Types

 

Introduction

When studying pointers, we saw that the compiler reserved an area in heap memory for the pointers of your application. We also saw that, when you declared a pointer and allocated memory using the new operator, you should remember to de-allocate the memory using the delete operator. Although modern compilers are equipped to check this, if you are working with one that would not empty the memory for you, your program could create a memory leak. The error being human, this has been one of the regular concerns when programming with C and C++. One of the improvements of C++/CLI was to assist you with this.

If you (decide to) use pointers in your program, the heap memory is highly under your control. Notice that we use "if". This means that, in C++, you can create a complete program that doesn't, or hardly, use pointers. For a serious programmer, there is no way you can simply decide not to use pointers at all. Since you are going to use them, as we mentioned, the compiler reserves some heap memory for you. If you don't manage it right, you can create a mess. To avoid this, no more "if", the common language runtime (CLR) suggests and sometimes requires that you use another technique. This time, instead of your being in control of that heap, the compiler sets aside its own portion of heap and becomes in charge of it. To differentiate both portions of memory, the heap we mentioned when studying pointers is referred to as native heap. The heap used by the CLR is called the managed heap:

Computer Memory
 

Practical LearningPractical Learning: Introducing Handles

  1. To start a new program, on the main menu, click File -> New -> Project...
  2. On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
  3. In the Name box, replace the string with RealEstate6 and click OK
  4. To create a source file, on the main menu, click Project -> Add New Item...
  5. In the Templates list, click Source File (.cpp)
  6. In the New box, type Exercise and click Add
  7. In the empty file, type:
    using namespace System;
    
    int main()
    {
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        return 0;
    }
  8. To execute the application, on the main menu, click Debug -> Start Without Debugging
  9. Click Yes
  10. On the main menu, click Project -> Add New Item...
  11. In the Templates list, click Header File (.h)
  12. In the New box, type Property and click Add
  13. In the empty file, type the following:
    #pragma once
    
    namespace RealEstate
    {
        public value class CProperty
        {
        public:
            long PropertyNumber;
            __wchar_t PropertyType;
            unsigned Stories;
            unsigned Bedrooms;
            float Bathrooms;
            unsigned YearBuilt;
            double PropertyValue;
        };
    }
  14. Save the file

A Tracking Reference

In our introduction to pointers, we saw that a reference was a technique of declaring an additional variable that references a primary variable. This was viewed as creating a variable that simply referred to another previously declared variable. Such a variable declared as a reference is stored in the stack. The compiler is then in charge of “cleaning” it, that is, in charge of reclaiming its memory when the reference is not used anymore. C++/CLI allows you to declare a reference that, if you want, would be stored in the CLR heap so the garbage collector would be in charge of managing it. Such a variable is called a tracking reference.

As done for a primitive type, you can also create a tracking reference of a class. To start, declare and initialize a variable of the class. Once the referenced variable is ready, to create a tracking reference, declare the variable but type the % operator between the class name and the name of the variable. To indicate the variable it is referencing, assign it the variable that was previously defined. Here is an example:

int main()
{
	CProperty victorian;

	victorian.Value = 485565;

	CProperty % single = victorian;

	return 0;
}

You can then access the members of either the referenced or the referencing variables. If you change the values of the members of the variable, the values of the reference would be changed also. In the same way, if you change the values of the reference, the values of the referenced variable would be changed also. 

Creating a Handle

To store a variable in the managed heap, you must create it as a handle. To create a handle, as opposed to the asterisk "*" of a pointer, you use the cap "^" operator. Here is an example:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty ^ townhome;

	Console::WriteLine();
	return 0;
}

As mentioned for the ampersand & operator of the reference and the asterisk operator of the pointer, there are three basic positions the cap operator ^ can have:

CProperty^ townhome;
CProperty ^ townhome;
CProperty ^townhome;

The compiler will assume the same. In this case, townhome is a handle to CProperty.

When studying pointers, we mentioned that you could not initialize a newly created pointer with just any value. You could initialize it with 0, which represented the null value. To initialize a handle with a null value, you can assign it the nullptr value. Here is an example:

int main()
{
	CProperty ^ townhome = nullptr;

	Console::WriteLine();
	return 0;
}

After creating a handle, you should let the compiler know what variable it handles. To do this, assign it a declared variable preceded with the % operator, as we did for the & operator when referencing a pointer. Here is an example:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty townhouse;

	townhouse.YearBuilt = 1986;
	townhouse.NumberOfBathrooms = 1.5;
	townhouse.Stories = 3;
	townhouse.Value = 348255;
	townhouse.NumberOfBedrooms = 3;
	townhouse.TypeOfHome = L'T';

	CProperty ^ townhome = %townhouse;

	Console::WriteLine();
	return 0;
}

Practical LearningPractical Learning: Creating a Handle

  1. Access the Exercise.cpp file
  2. To create a handle, declare a CProperty variable as follows:
    #include "Property.h"
    
    using namespace System;
    using namespace RealEstate;
    
    int main()
    {
        CProperty ^ house;
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        return 0;
    }
  3. Save the Exercise.cpp file

Reference Types

In Lesson 4, we saw that you could create a class using the value keyword on the left of the struct or class keyword. If you create a class using the value keyword, when you declare a variable from that class, we have seen so far that you could store it in the stack by declaring it as a value type. Here is an example:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty victorian;

	victorian.Value = 485565;

	Console::Write("Property Value:      ");
	Console::WriteLine(victorian.Value);

	Console::WriteLine();
	return 0;
}

Alternatively, you can store the variable in the native heap. To do this, declare it as a pointer. Remember that if you declare the variable as a pointer, it is stored in the native heap and you must remember to reclaim its memory area when the program ends. This is done using the delete operator:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty * victorian = new CProperty;

	victorian->Value      = 485565;

	Console::Write("Property Value:      ");
	Console::WriteLine(victorian->Value);

	delete victorian ;

	Console::WriteLine();
	return 0;
}

If you want, you can store the variable in the managed heap by creating it as a handle:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty ^ victorian = gcnew CProperty;

	victorian->Value      = 485565;

	Console::Write("Property Value:      ");
	Console::WriteLine(victorian->Value);

	Console::WriteLine();
	return 0;
}

As seen already, you can also create a reference to a class type. This means that you have a choice of storing the variable in the stack, the native heap, or the managed heap. Besides the value keyword, you can create a class using the ref keyword. Here is an example:

public ref class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

In most cases, you can use a ref class as you would a value class. There are still many differences between both types. One of the rules you must observes is that you cannot create a native reference of ref class. For example, the following program will compile:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty victorian;

	victorian.Value = 485565;

	CProperty & single = victorian;

	Console::Write("Property Value:      ");
	Console::WriteLine(victorian.Value);

	Console::Write("Property Value:      ");
	Console::WriteLine(single.Value);

	Console::WriteLine();
	return 0;
}

The following will not compile:

using namespace System;

public ref class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty victorian;

	victorian.Value = 485565;

	CProperty & single = victorian;

	Console::Write("Property Value: ");
	Console::WriteLine(victorian.Value);

	Console::Write("Property Value: ");
	Console::WriteLine(single.Value);

	Console::WriteLine();
	return 0;
}

When compiling it in Microsoft Visual C++ 2008, this program would produce a C3699, a C2440, and a C2228 errors:

error C3699: '&' : cannot use this indirection on type 'CProperty'
        compiler replacing '&' with '^' to continue parsing
error C2440: 'initializing' : cannot convert from 'CProperty' to 'CProperty ^'
        No user-defined-conversion operator available, or
        No user-defined-conversion operator available that can perform 
	this conversion, or the operator cannot be called
.\Exercise.cpp(26) : error C2228: left of '.Value' must have class/struct/union
        type is 'CProperty ^'
        did you intend to use '->' instead?

The reason this will not compile is that, if you create a class as ref or if you use a class that was created as ref, you cannot create a native reference of it. If you want to create a reference and if you are the one creating a class, make it a value type. If you created the class as ref, or if you are using a ref class that was created by someone else, you can create a tracking reference of it. Based on this, the following instead will work:

using namespace System;

public ref class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty victorian;

	victorian.Value = 485565;

	CProperty % single = victorian;

	Console::Write("Property Value: ");
	Console::WriteLine(victorian.Value);

	Console::Write("Property Value: ");
	Console::WriteLine(single.Value);

	Console::WriteLine();
	return 0;
}

Remember that you can also create a handle to use it.

Practical LearningPractical Learning: Creating a Reference Class

  1. Access the Property.h file
  2. To make the class a reference type, change it as follows:
    #pragma once
    
    namespace RealEstate
    {
        public ref class CProperty
        {
        public:
            long PropertyNumber;
            __wchar_t PropertyType;
            unsigned Stories;
            unsigned Bedrooms;
            float Bathrooms;
            unsigned YearBuilt;
            double PropertyValue;
        };
    }
  3. Save the Property.h file

Accessing the Members of a Handle

After creating a handle, you can access its members. As done for the pointer, you have two alternatives. You can use the asterisk "*" on the left side of a handle. After including the asterisk and the handle between parentheses, you can use the period operator to access each member. This allows you either to initialize the member or to retrieve its current value. Here are examples:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty apartment;

	apartment.YearBuilt = 2002;
	apartment.NumberOfBathrooms = 1;
	apartment.Stories = 18;
	apartment.Value = 155825;
	apartment.NumberOfBedrooms = 2;
	apartment.TypeOfHome = L'C';

	CProperty ^ condo = %apartment;

	Console::Write("Type of Home:        ");
	Console::WriteLine((*condo).TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine((*condo).NumberOfBedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine((*condo).NumberOfBathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine((*condo).Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine((*condo).YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine((*condo).Value);

	Console::WriteLine();
	return 0;
}

Instead of the asterisk, you can use the arrow, as done for the pointer, to access the members of a handle. The above program can produce the same results with:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty apartment;

	apartment.YearBuilt = 2002;
	apartment.NumberOfBathrooms = 1;
	apartment.Stories = 18;
	apartment.Value = 155825;
	apartment.NumberOfBedrooms = 2;
	apartment.TypeOfHome = L'C';

	CProperty ^ condo = %apartment;

	Console::Write("Type of Home:        ");
	Console::WriteLine(condo->TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(condo->NumberOfBedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(condo->NumberOfBathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(condo->Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(condo->YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(condo->Value);

	Console::WriteLine();
	return 0;
}

Both notations produce the same result:

Type of Home:        C
Number of Bedrooms:  2
Number of Bathrooms: 1
Number of Stories:   18
Year Built:          2002
Monetary Value:      155825

Press any key to continue . . .

Using the Garbage Collector

We saw that there were some details related to using the native heap: you could hesitate to use or not to use pointers, you could forget to delete pointers, you could even misuse it. To solve these and some other problems, the common language runtime reserves its own portion of the garbage collected heap to make available when you use handles. Based on this, when creating a handle, to allocate memory for it, you can instantiate it using the gcnew operator. The formula to use it is:

ClassName ^ HandleName = gcnew ClassName;

The ClassName is the class whose handle you want to create.

The ^, =, and gcnew operators are required.

The HandleName is the name of the handle that will be created.

After creating the handle, you can assign the desired value to each of its members. Here are examples:

using namespace System;

public value class CProperty
{
public:
	__wchar_t TypeOfHome;
	int NumberOfBedrooms;
	double NumberOfBathrooms;
	Byte Stories;
	int YearBuilt;
	double Value;
};

int main()
{
	CProperty ^condominium = gcnew CProperty;

	condominium->YearBuilt = 2002;
	condominium->NumberOfBathrooms = 1;
	condominium->Stories = 18;
	condominium->Value = 155825;
	condominium->NumberOfBedrooms = 2;
	condominium->TypeOfHome = L'C';

	Console::Write("Type of Home:        ");
	Console::WriteLine(condominium->TypeOfHome);
	Console::Write("Number of Bedrooms:  ");
	Console::WriteLine(condominium->NumberOfBedrooms);
	Console::Write("Number of Bathrooms: ");
	Console::WriteLine(condominium->NumberOfBathrooms);
	Console::Write("Number of Stories:   ");
	Console::WriteLine(condominium->Stories);
	Console::Write("Year Built:          ");
	Console::WriteLine(condominium->YearBuilt);
	Console::Write("Monetary Value:      ");
	Console::WriteLine(condominium->Value);

	Console::WriteLine();
	return 0;
}

Unlike a pointer whose memory was allocated with the new operator, when a handle is not used anymore, you don't need to de-allocate its memory. The garbage collector would take care of it. If you insist, you can still use the delete operator to remove the handle from memory. You use the delete operator the exact same way we did for the pointer.

Practical LearningPractical Learning: Initializing a Handle

  1. Access the Exercise.cpp file
  2. To initialize the declared handle, change it as follows:
    #include "Property.h"
    
    using namespace System;
    using namespace RealEstate;
    
    int main()
    {
        CProperty ^ house = gcnew CProperty;
    
        house->PropertyNumber = 792749;
        house->PropertyType = 'S';
        house->Stories = 2;
        house->Bedrooms = 4;
        house->Bathrooms = 2.0f;
        house->YearBuilt = 1956;
        house->PropertyValue = 412650;
    
        Console::WriteLine("=//= Altair Realty =//=");
        Console::WriteLine("-=- Properties Inventory -=-");
        Console::Write("Property #:   ");
        Console::WriteLine(house->PropertyNumber);
        Console::Write("Type:         ");
        Console::WriteLine(house->PropertyType);
        Console::Write("Bedrooms:     ");
        Console::WriteLine(house->Bedrooms);
        Console::Write("Bathrooms:    ");
        Console::WriteLine(house->Bathrooms);
        Console::Write("Stories:      ");
        Console::WriteLine(house->Stories);
        Console::Write("Year Built:   ");
        Console::WriteLine(house->YearBuilt);
        Console::Write("Market Value: ");
        Console::WriteLine(house->PropertyValue);
        
        return 0;
    }
  3. Execute the application to see the result:
    =//= Altair Realty =//=
    -=- Properties Inventory -=-
    Property #:   792749
    Type:         S
    Bedrooms:     4
    Bathrooms:    2
    Stories:      2
    Year Built:   1956
    Market Value: 412650
    Press any key to continue . . .
  4. Close the DOS window

Previous Copyright © 2006-2025, FunctionX Monday 14 October 2024, 10:12 Next