Home

Fundamentals of Classes and Indexed Properties

 

Introduction

We learned to create and use indexed properties that were taking parameters of primitive types. Just as we did with primitive types, you can create an indexed property that is of a class type. For example, you can create a class so that one of the its member variables declared as an array can be accessed with an index directly applied to an instance of the class.

 

Practical Learning: Introducing Indexers and Classes

  1. Start Microsoft Visual C++ 2005 or Microsoft Visual C++ 2005 Express Edition
  2. To start a new project, on the main menu, click File -> New -> Project...
  3. In the Project Types, make sure Visual C++ is selected.
    In the Templates list, click CLR Empty Project
  4. Set the name to PropertyRental2 and click OK
  5. To create a new class, on the main menu, click Project -> Add Class...
  6. In the Templates list, click C++ Class and click Acc
  7. Set the Name to CRentalProperty and click Finish
  8. Change the header file as follows:
     
    #pragma once
    
    using namespace System;
    
    public ref class CRentalProperty
    {
    private:
        long propCode;
        String ^ cond;
        short beds;
        double baths;
        double val;
    
    public:
        property long PropertyCode
        {
            long get() { return propCode; }
            void set(long value) { propCode = value; }
        }
    
        property String ^ PropertyCondition
        {
            String ^ get() { return cond; }
            void set(String ^ value) { cond = value; }
        }
    
        property short Bedrooms
        {
            short get() { return beds; }
            void set(short value) { beds = value; }
        }
    
        property double Bathrooms
        {
            double get() { return (baths <= 0) ? 0.00 : baths; }
            void set(double value) { baths = value; }
        }
    
        property double MonthlyRent
        {
            double get() { return (val <= 0) ? 0.00 : val; }
            void set(double value) { val = value; }
        }
    
    public:
    	CRentalProperty(void);
    	virtual String ^ ToString() override;
    };
  9. Open the RentalProperty.cpp file and change it as follows:
     
    #include "RentalProperty.h"
    
    CRentalProperty::CRentalProperty(void)
    {
        Random ^ rnd = gcnew Random();
        propCode = rnd->Next(100000, 999999);
        cond = L"Unknown";
        beds = 0;
        baths = 0.0;
        val = 0.00;
    }
    
    String ^ CRentalProperty::ToString()
    {
        return L"Property #:   " + PropertyCode +
               L"\nCondition:    " + PropertyCondition +
               L"\nBedrooms:     " + Bedrooms +
               L"\nBathrooms:    " + Bathrooms +
               L"\nMonthly Rent: " + MonthlyRent.ToString("C");
    };
  10. To create a new class, on the main menu, click Project -> Add Class...
  11. In the Templates list, make sure C++ Class is selected and click Add
  12. Set the Name to CPropertyListing and press Enter
  13. Change the header file as follows:
     
    #pragma once
    
    #include "RentalProperty.h"
    
    public ref class CPropertyListing
    {
    public:
        array<CRentalProperty ^> ^ props;
    
        property String ^ default[long]
        {
            String ^ get(long code)
            {
                for (int i = 0; i < props->Length; i++)
                    if (code == props[i]->PropertyCode)
                        return L"Property #:   " + 
    				props[i]->PropertyCode +
                               L"\nCondition:    " + 
    				props[i]->PropertyCondition +
                               L"\nBedrooms:     " + 
    				props[i]->Bedrooms +
                               L"\nBathrooms:    " + 
    				props[i]->Bathrooms +
                               L"\nMonthly Rent: " + 
    				props[i]->MonthlyRent.ToString("C");
                return L"Unidentifiable Property";
            }
        }
    public:
    	CPropertyListing(void);
    };
  14. Access the PropertyListing.cpp source file and change it as follows:
     
    #include "PropertyListing.h"
    
    CPropertyListing::CPropertyListing(void)
    {
        Random ^ rnd = gcnew Random;
        props = gcnew array<CRentalProperty ^>(40);
    
        // Create a few properties ready to be rented
        props[0] = gcnew CRentalProperty;
        props[0]->PropertyCode = rnd->Next(100000, 999999);
        props[0]->PropertyCondition = L"Excellent";
        props[0]->Bedrooms = 5;
        props[0]->Bathrooms = 3.5;
        props[0]->MonthlyRent = 2650;
    
        props[1] = gcnew CRentalProperty;
        props[1]->PropertyCode = rnd->Next(100000, 999999);
        props[1]->PropertyCondition = L"Excellent";
        props[1]->Bedrooms = 3;
        props[1]->Bathrooms = 2.5;
        props[1]->MonthlyRent = 1750;
    
        props[2] = gcnew CRentalProperty;
        props[2]->PropertyCode = rnd->Next(100000, 999999);
        props[2]->PropertyCondition = L"Good";
        props[2]->Bedrooms = 4;
        props[2]->Bathrooms = 2.5;
        props[2]->MonthlyRent = 2450;
    
        props[3] = gcnew CRentalProperty;
        props[3]->PropertyCode = rnd->Next(100000, 999999);
        props[3]->PropertyCondition = L"Excellent";
        props[3]->Bedrooms = 1;
        props[3]->Bathrooms = 1.0;
        props[3]->MonthlyRent = 880;
    
        props[4] = gcnew CRentalProperty;
        props[4]->PropertyCode = rnd->Next(100000, 999999);
        props[4]->PropertyCondition = L"Excellent";
        props[4]->Bedrooms = 3;
        props[4]->Bathrooms = 2.5;
        props[4]->MonthlyRent = 1880;
    
        props[5] = gcnew CRentalProperty;
        props[5]->PropertyCode = rnd->Next(100000, 999999);
        props[5]->PropertyCondition = L"Good";
        props[5]->Bedrooms = 2;
        props[5]->Bathrooms = 1.0;
        props[5]->MonthlyRent = 1050;
    
        // Since we don't yet have a complete list of properties
        // Create some empty ones
        for (int i = 6; i < 40; i++)
        {
            props[i] = gcnew CRentalProperty;
        }
    }
  15. To create a new file, on the main menu, click Project -> Add New Item...
  16. In the Templates list, click C++ File (.cpp)
  17. Set the name to Exercise and click OK
  18. Implement the file as follows:
     
    using namespace System;
    
    #include "PropertyListing.h"
    
    int main()
    {
        CPropertyListing ^ properties = gcnew CPropertyListing;
        long lngCode;
    
        Console::WriteLine(L"Here is a list of our properties by code");
        for (int i = 0; i < 6; i++)
            Console::WriteLine(L"Property Code: {0}",
    		properties->props[i]->PropertyCode);
    
        try
        {
    	Console::Write("Enter Property Code: ");
    	lngCode = long::Parse(Console::ReadLine());
    
            Console::WriteLine(L"======================================");
            Console::WriteLine(L"Property Information");
            Console::WriteLine(L"--------------------------------------");
            Console::WriteLine(properties[lngCode]);
            Console::WriteLine(L"======================================");
        }
        catch(FormatException ^)
        {
            Console::WriteLine(L"=- Invalid Property Code -=");
        }
    
        return 0;
    }
  19. Press Ctrl + F5 to execute the application. Here is an example:
     
    Here is a list of our properties by code
    Property Code: 355443
    Property Code: 653004
    Property Code: 800118
    Property Code: 839375
    Property Code: 148561
    Property Code: 697001
    Enter Property Code: 697001
    ======================================
    Property Information
    --------------------------------------
    Property #:   697001
    Condition:    Good
    Bedrooms:     2
    Bathrooms:    1
    Monthly Rent: $1,050.00
    ======================================
    Press any key to continue . . .
  20. Close the DOS window

An Integer-Based Indexed Property

Before designing an indexed property that is class-based, first create the class that will be used as the data type. The class can be simple or complex as you judge it necessary. Here is an example of a simple class:

public ref class CStudent
{
public:
    String ^ FirstName;
    String ^ LastName;
    int      Gender;
};

When creating the class that will host the indexed property, declare an array member variable for the class. Then, create the default property with the desired accessor(s). Here is an example:

public ref class CStudent
{
public:
    String ^ FirstName;
    String ^ LastName;
    int      Gender;
};

public ref class CSchoolRegistration
{
    array<CStudent ^> ^ std;

public:
    property CStudent ^ default[int]
    {
        CStudent ^ get(int i) { return std[i]; }
    }

    CSchoolRegistration()
    {
	std = gcnew array<CStudent ^>(5);
    }
};

After creating the indexing class, you can use it and access the indexed property; for example, you can retrieve its value(s). Here is an example:

using namespace System;

public ref class CStudent
{
public:
    String ^ FirstName;
    String ^ LastName;
    int      Gender;
};

public ref class CSchoolRegistration
{
    array<CStudent ^> ^ std;

public:
    property CStudent ^ default[int]
    {
        CStudent ^ get(int i) { return std[i]; }
    }

    CSchoolRegistration()
    {
	std = gcnew array<CStudent ^>(5);
	
        std[0] = gcnew CStudent;
        std[0]->FirstName = L"Alfredo";
        std[0]->LastName = L"Olmos";
        std[0]->Gender = 2;

        std[1] = gcnew CStudent;
        std[1]->FirstName = L"Patricia";
        std[1]->LastName = L"Katts";
        std[1]->Gender = 1;

        std[2] = gcnew CStudent;
        std[2]->FirstName = L"Josiane";
        std[2]->LastName = L"Euler";
        std[2]->Gender = 1;

        std[3] = gcnew CStudent;
        std[3]->FirstName = L"Joan";
        std[3]->LastName = L"Jones";
        std[3]->Gender = 3;

        std[4] = gcnew CStudent;
        std[4]->FirstName = L"George";
        std[4]->LastName = L"Paulson";
        std[4]->Gender = 2;
    }
};

int main()
{
    CSchoolRegistration ^ pupils = gcnew CSchoolRegistration;

    for (int i = 0; i < 5; i++)
    {
        CStudent ^ pupil = pupils[i];

        Console::WriteLine(L"Student Information");
        Console::WriteLine(L"---------------------");
        Console::WriteLine(L"First Name: {0}", pupil->FirstName);
        Console::WriteLine(L"Last Name:  {0}", pupil->LastName);
        Console::WriteLine(L"Gender:     {0}\n",
                             (pupil->Gender == 1 ? "Female" :
                             (pupil->Gender == 2 ? "Male" : "Unknown")));
    }

    Console::WriteLine();
    return 0;
}

This would produce:

Student Information
---------------------
First Name: Alfredo
Last Name:  Olmos
Gender:     Male

Student Information
---------------------
First Name: Patricia
Last Name:  Katts
Gender:     Female

Student Information
---------------------
First Name: Josiane
Last Name:  Euler
Gender:     Female

Student Information
---------------------
First Name: Joan
Last Name:  Jones
Gender:     Unknown

Student Information
---------------------
First Name: George
Last Name:  Paulson
Gender:     Male

Press any key to continue . . .

Practical Learning: Using an Integer-Based Indexer

  1. To create an indexed property that takes an integer and returns an object, access the PropertyListing.h header file and change it as follows:
     
    #pragma once
    
    #include "RentalProperty.h"
    
    public ref class CPropertyListing
    {
    public:
        array<CRentalProperty ^> ^ props;
    
        property CRentalProperty ^ default[int]
        {
            CRentalProperty ^ get(int i) { return props[i]; }
        }
    
        property String ^ default[long]
        {
            String ^ get(long code)
            {
                . . . No Change
            }
        }
    public:
    	CPropertyListing(void);
    };
  2. Access the Exercise.cpp source file and change it as follows:
     
    using namespace System;
    
    #include "PropertyListing.h"
    
    int main()
    {
        CPropertyListing ^ properties = gcnew CPropertyListing;
    
        Console::WriteLine(L"Here is a list of our properties");
        for (int i = 0; i < 6; i++)
        {
            CRentalProperty ^ prop = properties[i];
    
            Console::WriteLine(L"Property Information");
            Console::WriteLine(L"--------------------------------------");
            Console::WriteLine(L"Property #:   {0}", prop->PropertyCode);
            Console::WriteLine(L"Condition:    {0}", prop->PropertyCondition);
            Console::WriteLine(L"Bedrooms:     {0}", prop->Bedrooms);
            Console::WriteLine(L"Bathrooms:    {0}", prop->Bathrooms);
            Console::WriteLine(L"Monthly Rent: {0}", 
    		prop->MonthlyRent.ToString("C"));
            Console::WriteLine(L"======================================");
        }
    
        return 0;
    }
  3. Press Ctrl + F5 to execute the application
  4. Close the DOS window

An Indexed Property Using Another Primitive Type

The above implementation of the CSchoolRegistration class easily allowed us to locate an element of the array by specifying its integer-based index. As done for primitive types, an indexed property can take a parameter other than an integer. In some cases, you may use your class or a class created by someone else and need to access an element of the array without information other than its index. Consider the following program:

public ref class CStudent
{
};

public ref class CSchoolRegistration
{
    array<CStudent ^> ^ students;

public:
    property CStudent ^ default[...]
    {
    }

    CSchoolRegistration()
    {
	students = gcnew array<CStudent ^>(50);
    }
};

Previously, we saw that you could create an indexed property that took a type other than an integer. For example, we saw that a string could be used as an index.

By now, we know that a basic indexed property produces (or all the indexed properties we have studied so far produce) only one value. If you have a class that has only one member variable, this would be enough. In reality, most of the time, a class has many member variables. In such a case, when you create an indexed property , you need to be able to refer to one exact element of the array. To make this possible, you must define a way to point to the particular element you want. One way you can do this is to use one member variable of the class as a reference. This is better if that member variable holds unique values among the other elements of the array. For our CStudent class, we could use the StudentID member variable (because we will make sure that each student has a unique ID). You can start the property as follows:

public ref class CSchoolRegistration
{
public:
    property CStudent ^ default[long]
    {
    }
};

When a user uses this property, he or she must provide a value that uniquely identifies an element of the array. You in turn, when you get this value, you can search for it in the array. If you find it and the array has a get accessor, you can then return the desired but appropriate value. Here is how this can be done:

public ref class CSchoolRegistration
{
    array<CStudent ^> ^ students;

public:
    property CStudent ^ default[long]
    {
        CStudent ^ get(long id)
        {
            for (int i = 0; i < students->Length; i++)
            {
                if (students[i]->StudentID == id)
                    return students[i];
            }
            // Unknown student or the number was not found
            return nullptr;
        }
    }

    CSchoolRegistration()
    {
	students = gcnew array<CStudent ^>(50);
    }
};

After creating the indexed property, you can use it. Once again, you must follow the rules of a method that takes an argument and returns a value other than void. In this case, the indexed property must take a string and it must return a CStudent object. Here is an example:

using namespace System;

public enum Classification
{
    Female,
    Male,
    Unknown
};

public ref class CStudent
{
public:
    long StudentID;
    String ^ FirstName;
    String ^ LastName;
    Classification Gender;

    virtual String ^ ToString() override
    {
	String ^ str = String::Concat(L"Student ID: ", 
			StudentID.ToString(),
                       L"\nFirst Name: ", FirstName,
                       L"\nLast Name:  ", LastName,
                       L"\nGender:     ", Gender);
        return str;
    }
};

public ref class CSchoolRegistration
{
    array<CStudent ^> ^ students;

public:
	property CStudent ^ default[long]
    {
        CStudent ^ get(long id)
        {
            for (int i = 0; i < students->Length; i++)
            {
                if (students[i]->StudentID == id)
                    return students[i];
            }
            // Unknown student or the number was not found
            return nullptr;
        }
    }

    CSchoolRegistration()
    {
	students = gcnew array<CStudent ^>(50);

        students[0] = gcnew CStudent;
        students[0]->StudentID = 917294;
        students[0]->FirstName = L"Helene";
        students[0]->LastName = L"Mukoko";
	students[0]->Gender = Female;

        students[1] = gcnew CStudent;
        students[1]->StudentID = 283764;
        students[1]->FirstName = L"Patrice";
        students[1]->LastName = L"Katts";
        students[1]->Gender = Unknown;

        students[2] = gcnew CStudent;
        students[2]->StudentID = 192046;
        students[2]->FirstName = L"Armand";
        students[2]->LastName = L"Essono";
        students[2]->Gender = Male;

        students[3] = gcnew CStudent;
        students[3]->StudentID = 618268;
        students[3]->FirstName = L"Bertrand";
        students[3]->LastName = L"Yamaguchi";
        students[3]->Gender = Male;

        students[4] = gcnew CStudent;
        students[4]->StudentID = 820648;
        students[4]->FirstName = L"Hortense";
        students[4]->LastName = L"McNeal";
        students[4]->Gender = Female;
    }
};

int main()
{
    CSchoolRegistration ^ pupils = gcnew CSchoolRegistration;

    CStudent ^ pupil = pupils[820648];

    Console::WriteLine(L"Student Information");
    Console::WriteLine(L"---------------------");
    Console::WriteLine(L"First Name: {0}", pupil->FirstName);
    Console::WriteLine(L"Last Name:  {0}", pupil->LastName);
    Console::Write(L"Gender:     ");
	Console::WriteLine(pupil->Gender);

    pupil = pupils[192046];

    Console::WriteLine(L"Student Information");
    Console::WriteLine(L"---------------------");
    Console::WriteLine(L"First Name: {0}", pupil->FirstName);
    Console::WriteLine(L"Last Name:  {0}", pupil->LastName);
    Console::Write(L"Gender:     ");
    Console::WriteLine(pupil->Gender);

    return 0;
}

This would produce:

Student Information
---------------------
First Name: Hortense
Last Name:  McNeal
Gender:     Female

Student Information
---------------------
First Name: Armand
Last Name:  Essono
Gender:     Male

Press any key to continue . . .

 

 

 

 

 

 

 

Home Copyright © 2007-2012 FunctionX Next