A Property Can Be Indexed
|
Introduction
|
In Lesson 25, we learned how to create an array,
how to assign values to its elements, and how to get the value of each element. Here is an example:
using namespace System; int main() { array<double> ^ Numbers = gcnew array<double>(5); Numbers[0] = 927.93; Numbers[1] = 45.155; Numbers[2] = 2.37094; Numbers[3] = 73475.25; Numbers[4] = 186.72; for(int i = 0; i < Numbers->Length; i++) Console::WriteLine(L"Number {0}: {1}", i+1, Numbers[i]); Console::WriteLine(); return 0; }
This would produce:
Number 1: 927,93 Number 2: 45,155 Number 3: 2,37094 Number 4: 73475,25 Number 5: 186,72 Press any key to continue . . .
In the same way, if we declared an array as a
member variable of a class, to access the elements of that member, we had to use
an instance of the class, followed by the period operator, followed by the
member variable applied with the square brackets. Instead of accessing each element through its member
variable, you can create a type of property referred to as an indexer.
|
- Start Microsoft Visual C++ 2005
- To start a new, on the main menu, click File -> New -> Project...
- In the Project Types, make sure Visual C++ is selected.
In the Templates list, click CLR Empty Project - Set the Name to PropertyRental1
- To create a new class, on the main menu, click Project -> Add Class...
- In the Categories, select C++.
In the Templates list, click C++ Class and click Add - Set the Name to CRentalProperty and click Finish Enter
- Change the file as follows:
#pragma once using namespace System; public ref class CRentalProperty { public: 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; } } CRentalProperty(void); };
- Access the RentalProperty.cpp file and change the constructor 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; }
- To create a new class, on the main menu, click Project -> Add Class...
- In the Categories, make sure C++ is selected.
In the Templates list, click C++ Class and click Finish - Set the Name to CPropertyListing and click Finish
- Change the file as follows:
#pragma once #include "RentalProperty.h" public ref class CPropertyListing { public: array<CRentalProperty ^> ^ props; public: CPropertyListing(void); };
-
Access the PropertyListing.cpp file and change the constructor 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; } }
- To create a new file, on the main menu, click Project -> Add New Item...
- In the Categories, click Code
- In the Templates list, click C++ File (.cpp)
- Set the Name to Exercise and click Add
- Access the Program.cs file and change it as follows:
using namespace System; #include "PropertyListing.h" int main() { CPropertyListing ^ properties = gcnew CPropertyListing; CRentalProperty ^ prop = gcnew CRentalProperty; for(int i = 0; i < 6; i++) { Console::WriteLine(L"{0}.----------------------------------", i + 1); Console::WriteLine(L"Property #: {0}", properties->props[i]->PropertyCode); Console::WriteLine(L"Condition: {0}", properties->props[i]->PropertyCondition); Console::WriteLine(L"Bedrooms: {0}", properties->props[i]->Bedrooms); Console::WriteLine(L"Bathrooms: {0}", properties->props[i]->Bathrooms); Console::WriteLine(L"Market Value: {0}\n", properties->props[i]->MonthlyRent.ToString("C")); } Console::WriteLine(L"======================================"); return 0; }
- Press Ctrl + F5 to execute the application. This would produce:
1.---------------------------------- Property #: 920119 Condition: Excellent Bedrooms: 5 Bathrooms: 3.5 Market Value: $2,650.00 2.---------------------------------- Property #: 587917 Condition: Excellent Bedrooms: 3 Bathrooms: 2.5 Market Value: $1,750.00 3.---------------------------------- Property #: 904376 Condition: Good Bedrooms: 4 Bathrooms: 2.5 Market Value: $2,450.00 4.---------------------------------- Property #: 421662 Condition: Excellent Bedrooms: 1 Bathrooms: 1 Market Value: $880.00 5.---------------------------------- Property #: 305196 Condition: Excellent Bedrooms: 3 Bathrooms: 2.5 Market Value: $1,880.00 6.---------------------------------- Property #: 503836 Condition: Good Bedrooms: 2 Bathrooms: 1 Market Value: $1,050.00 ====================================== Press any key to continue . . .
- Close the DOS window
An Indexed Property
|
An indexer, also called an indexed property, is a class's property that allows you to
access a member variable of a class using the features of an array. To create an
indexed property, start the class like any other. In the body of the class,
create a member variable that is an array and initialize it appropriately. Here is an example:
public ref class CNumber { array<double> ^ Numbers; public: CNumber() { Numbers = gcnew array<double>(5); } };
Then, in the body of the class, create a property named default
with its accessor(s).
The default property must be the same type as the member variable it will refer to. The
property must take a parameter as an array. This means that it must have square
brackets. Inside of the brackets, include the parameter type you will use as index to access
the members of the array.
Traditionally, and as we have seen so far, you usually
access the members of an array using an integer-based index. Therefore, you can
use an int type as the index of the array but the index'
parameter must not have a name. This would be done as follows:
public ref class CNumber { array<double> ^ Numbers = gcnew double[5]; public: property double default[int] { } }
If you want the property to be read-only, include only a get
accessor.
When creating the get accessor, you must pass a
parameter to it. The parameter must be the same type you passed to the default
property, except that, as mentioned above, the parameter passed to default
must not have a name but the parameter passed to get must have a name.
When implementing the get accessor, it must return an element of the
array member variable the
property refers to, using the parameter passed to get. This would be done as follows:
public ref class CNumber
{
array<double> ^ Numbers;
public:
CNumber()
{
Numbers = gcnew array<double>(5);
}
property double default[int]
{
double get(int i) { return Numbers[i]; }
}
};
Once you have created the indexed property, the class can be used. To start,
you can declare a handle of the class. To access its arrayed member variable, you can
apply the square brackets directly to it. Here is an example:
using namespace System;
public ref class CNumber
{
array<double> ^ Numbers;
public:
CNumber()
{
Numbers = gcnew array<double>(5);
Numbers[0] = 927.93;
Numbers[1] = 45.155;
Numbers[2] = 2.37094;
Numbers[3] = 73475.25;
Numbers[4] = 186.72;
}
property double default[int]
{
double get(int i) { return Numbers[i]; }
}
};
int main()
{
CNumber ^ nbr = gcnew CNumber;
for(int i = 0; i < 5; i++)
Console::WriteLine(L"Number {0}: {1}", i + 1, nbr[i]);
Console::WriteLine();
return 0;
}
Indexed Properties of Other Primitive Types
|
In the above example, we created a property that produced
double-precision values. When creating an indexed property, you will decide what
type of value the property must produce or the type it can have. As opposed
to an int or a double, you can also create a property that takes
or produces a string. Here is an example of a string-based
indexed property:
using namespace System;
public ref class CPhilosopher
{
array<String ^> ^ phil;
public:
property String ^ default[int]
{
String ^ get(int i) { return phil[i]; }
}
CPhilosopher()
{
phil = gcnew array<String ^>(8);
phil[0] = L"Aristotle";
phil[1] = L"Emmanuel Kant";
phil[2] = L"Tom Huffman";
phil[3] = L"Judith Jarvis Thompson";
phil[4] = L"Thomas Hobbes";
phil[5] = L"Cornell West";
phil[6] = L"Jane English";
phil[7] = L"James Rachels";
}
};
int main()
{
CPhilosopher ^ thinker = gcnew CPhilosopher;
for(int i = 0; i < 8; i++)
Console::WriteLine(L"Philosopher: {0}", thinker[i]);
Console::WriteLine();
return 0;
}
This would produce:
Philosopher: Aristotle Philosopher: Emmanuel Kant Philosopher: Tom Huffman Philosopher: Judith Jarvis Thompson Philosopher: Thomas Hobbes Philosopher: Cornell West Philosopher: Jane English Philosopher: James Rachels Press any key to continue . . .
In the same way, you can created a Boolean-based indexed
property by simply making it return a bool type. Here is an example:
using namespace System; public ref class CDrivingWhileIntoxicated { array<bool>^ dwi; public: property bool default[int] { bool get(int i) { return dwi[i]; } } CDrivingWhileIntoxicated() { dwi = gcnew array<bool>(7); dwi[0] = false; dwi[1] = true; dwi[2] = true; dwi[3] = false; dwi[5] = false; dwi[6] = false; } }; int main() { CDrivingWhileIntoxicated ^ driving = gcnew CDrivingWhileIntoxicated; Console::WriteLine(L"Police Report"); Console::WriteLine(L"-------------------------------"); for(int i = 0; i < 7; i++) Console::WriteLine(L"Driver Was Intoxicated: {0}", driving[i]); Console::WriteLine(); return 0; }
This would produce:
Police Report ------------------------------- Driver Was Intoxicated: False Driver Was Intoxicated: True Driver Was Intoxicated: True Driver Was Intoxicated: False Driver Was Intoxicated: False Driver Was Intoxicated: False Driver Was Intoxicated: False Press any key to continue . . .
Using a Non-Integer-Based Index
|
In Lesson 25, we saw how to create different arrays
that are numeric or string based. Here is an example of a float array:
using namespace System; int main() { array<float>^ ages = gcnew array<float>(5); ages[0] = 14.50f; ages[1] = 12.00f; ages[2] = 16.50f; ages[3] = 14.00f; ages[4] = 15.50f; Console::WriteLine(L"Student Age: {0}", ages[2]); Console::WriteLine(); return 0; }
When we think of arrays, we usually consider passing an
integer-based parameter to the square brackets of the variable, as done for the
above ages array:
array<float>^ ages = gcnew array<float>(5);
When using an indexed property, you can use almost any type
of index, such as a real value or a string. To do this, in the square brackets
of the default property, pass the desired type as the index. Here is an
example:
public ref class CStudentAge
{
property float default[string]
{
}
};
When defining the indexed property, there are two rules you
must follow and you are aware of them already because an indexed property is
like a method that takes a parameter and doesn't return void. Therefore,
when implementing an indexed property, make sure you return the right type of
value in the get accessor and make sure you pass the appropriate index to the return value of the
default property. Here is an example:
public ref class CStudentAge
{
public:
property float default[String ^]
{
float get(String ^ name)
{
if( name == L"Ernestine Jonas" )
return 14.50f;
else if( name == L"Paul Bertrand Yamaguchi" )
return 12.50f;
else if( name == L"Helene Jonas" )
return 16.00f;
else if( name == L"Chrissie Hanson" )
return 14.00f;
else if( name == L"Bernard Hallo" )
return 15.50f;
else
return 12.00f;
}
}
};
Once you have defined the property, you can use it. To
access any of its elements, you must pass the appropriate type of index. In this
case, the index must be passed as a string and not an integer. You can then do
whatever you want with the value produced by the property. For example, you can
display it to the user. Here is an example:
using namespace System;
public ref class CStudentAge
{
public:
property float default[String ^]
{
float get(String ^ name)
{
if( name == L"Ernestine Jonas" )
return 14.50f;
else if( name == L"Paul Bertrand Yamaguchi" )
return 12.50f;
else if( name == L"Helene Jonas" )
return 16.00f;
else if( name == L"Chrissie Hanson" )
return 14.00f;
else if( name == L"Bernard Hallo" )
return 15.50f;
else
return 12.00f;
}
}
};
int main()
{
CStudentAge ^ sa = gcnew CStudentAge;
float age = sa[L"Paul Bertrand Yamaguchi"];
Console::WriteLine(L"Student Age: {0}", age);
Console::WriteLine();
return 0;
}
This would produce:
Student Age: 12.5 Press any key to continue . . .
You can also pass an enumeration as an index. To do this,
after defining the enumerator, type its name in the square
brackets of the default member, then define the property as you see fit. To
access the property outside, apply an enumeration member to the square brackets
on an instance of the class. Here is an example:
using namespace System; public enum CategoryFee { Children, Adult, Senior, Unknown }; public ref class CGolfClubMembership { array<double> ^ fee; public: CGolfClubMembership() { fee = gcnew array<double>(4); fee[0] = 150.95; fee[1] = 250.75; fee[2] = 85.65; fee[3] = 350.00; } property double default[CategoryFee] { double get(CategoryFee cat) { if (cat == CategoryFee::Children) return fee[0]; else if (cat == CategoryFee::Adult) return fee[1]; else if (cat == CategoryFee::Senior) return fee[2]; else return fee[3]; } } }; int main() { CGolfClubMembership ^ mbr = gcnew CGolfClubMembership; Console::WriteLine(L"Membership Fee: {0}", mbr[CategoryFee::Senior]); Console::WriteLine(); return 0; }
This would produce:
Membership Fee: 85.65 Press any key to continue . . .
|
- To create an indexed propertyr, 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 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); };
- Access the Exercise.cpp file and change it 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(L"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; }
- 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 . . .
- Close the DOS window
Topics on Indexed Properties
|
Multi-Parameterized Indexed Properties
|
The indexed properties we have used so far were
taking only
one parameter. You can create an indexed property whose array uses more
than one
dimension. To start an indexed property that would use various
parameters, first declare the array. After declaring the array, create a
default property that takes the
parameters. Here is an example for an indexed property that relates to a
two-dimensional array:
public ref class CNumbers
{
array<double, 2> ^ nbr;
public:
property double default[int, int]
{
}
};
In the body of an accessor (get or set), use the parameter
as appropriately as you see fit. At a minimum, for a get accessor, you can
return the value of the array using the parameters based on the rules of a
two-dimensional array. This can be done as follows:
public ref class CNumbers
{
array<double, 2> ^ nbr;
public:
property double default[int, int]
{
double get(int i, int j) { return nbr[i,j]; }
}
};
After creating the property, you can access each element of
the array by applying the square brackets to an instance of the class. Here is
an example:
using namespace System;
public ref class CNumbers
{
array<double, 2> ^ nbr;
public:
property double default[int, int]
{
double get(int i, int j) { return nbr[i,j]; }
}
CNumbers()
{
nbr = gcnew array<double, 2>(2, 4);
nbr[0, 0] = 927.93;
nbr[0, 1] = 45.155;
nbr[0, 2] = 2.37094;
nbr[0, 3] = 73475.25;
nbr[1, 0] = 186.72;
nbr[1, 1] = 82.350;
nbr[1, 2] = 712734.95;
nbr[1, 3] = 3249.0057;
}
};
int main()
{
CNumbers ^ nbrs = gcnew CNumbers;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 4; j++)
{
double value = nbrs[i, j];
Console::WriteLine(L"Number [{0}][{1}]: {2}", i, j, value);
}
Console::WriteLine();
}
return 0;
}
Remember that one of the most valuable features of an
indexed property is that, when creating it, you can make it return any primitive
type and you can make it take any parameter of your choice. Also, the parameters
of a multi-parameter indexed property don't have to be the same type. One can be
a character while the other is a bool type; one can be a double while the
other is a short, one can be an integer while the other is a string. When
defining the property, you must apply the rules of both the methods and the
arrays. Here is an example of a property that takes an integer and a string:
using namespace System; public ref class CCatalog { array<long> ^ nbrs; array<String ^> ^ names; public: property double default[long, String ^] { double get(long nbr, String ^ name) { if( (nbr == nbrs[0]) && (name == names[0]) ) return 275.25; else if( (nbr == nbrs[1]) && (name == names[1]) ) return 18.75; else if( (nbr == nbrs[2]) && (name == names[2]) ) return 50.00; else if( (nbr == nbrs[3]) && (name == names[3]) ) return 65.35; else if( (nbr == nbrs[4]) && (name == names[4]) ) return 25.55; else return 0.00; } } CCatalog() { nbrs = gcnew array<long>(5); nbrs[0] = 273974; nbrs[1] = 539759; nbrs[2] = 710234; nbrs[3] = 220685; nbrs[4] = 192837; names = gcnew array<String ^>(5); names[0] = L"Women Double-faced wool coat"; names[1] = L"Men Cotton Polo Shirt"; names[2] = L"Children Cable-knit Sweater"; names[3] = L"Women Floral Silk Tank Blouse"; names[4] = L"Girls Jeans with Heart Belt"; } }; int main() { CCatalog ^ cat = gcnew CCatalog; long itemNumber = 539759; String ^ itemDescription = L"Men Cotton Polo Shirt"; double price = cat[itemNumber, itemDescription]; Console::WriteLine(L"Item #: {0}", itemNumber); Console::WriteLine(L"Description: {0}", itemDescription); Console::WriteLine(L"Unit Price: {0}", price); Console::WriteLine(); return 0; }
This would produce:
Item #: 539759 Description: Men Cotton Polo Shirt Unit Price: 18.75 Press any key to continue . . .
In the above example, we first declared the variables to be
passed as parameters to the indexed property. You can also pass the parameter(s)
directly to the instance of the class. Here is an example:
int main()
{
CCatalog ^ cat = gcnew CCatalog;
double price = cat[220685, L"Women Floral Silk Tank Blouse"];
Console::WriteLine(L"Item #: 220685");
Console::WriteLine(L"Description: {Women Floral Silk Tank Blouse");
Console::WriteLine(L"Unit Price: {0}", price);
Console::WriteLine();
return 0;
}
Just as you can create a two-dimensional indexed property,
you can also create a property that takes more than two parameters. Once again,
it is up to you to decide what type of parameter would be positioned where in
the square brackets. Here is an example of an indexed property that takes three
parameters:
using namespace System; public ref class CCatalog { public: property String ^ default[long, String ^, double] { String ^ get(long nbr, String ^ name, double price) { return L"Item #: " + nbr.ToString() + L"\n" + L"Description: " + name + "\n" + L"Unit Price: " + price.ToString(L"C"); } } }; int main() { CCatalog ^ cat = gcnew CCatalog; Console::WriteLine(L"Item Description"); Console::WriteLine(cat[220685, L"Women Floral Silk Tank Blouse", 50.00]); Console::WriteLine(); return 0; }
Overloading an Indexed Property
|
An indexed property borrows various characteristics of a method. One
of them is the ability to create various indexers in the same class but all of
them must have the same name: default. Still, the various indexed
properties of a class can
return the same type of value. Because of this, when creating the indexed
properties, you
must find a way to distinguish them. One way you can do this, as seen with
function or method overloading, consists of passing a different type of parameter to each
indexed property. This is referred to as overloading.
To overload the default property, if two indexed properties take only one parameter, each must take a
different (data) type of parameter than the other. Here is an example:
using namespace System; public ref class CStudentIdentifications { array<int> ^ studentIDs; array<String ^> ^ fullnames; // This property takes a student ID, as an integer, // and it produces his/her name public: property String ^ default[int] { String ^ get(int i) { for(int i = 0; i < studentIDs->Length; i++) if( i == studentIDs[i] ) return fullnames[i]; return L"Unknown Student"; } } // This property takes a student name, as a string, // and it produces his/her student ID property int default[String ^] { int get(String ^ name) { for(int i = 0; i < fullnames->Length; i++) if( name == fullnames[i] ) return studentIDs[i]; return 0; } } CStudentIdentifications() { studentIDs = gcnew array<int>(6); studentIDs[0] = 39472; studentIDs[1] = 13957; studentIDs[2] = 73957; studentIDs[3] = 97003; studentIDs[4] = 28947; studentIDs[5] = 97395; fullnames = gcnew array<String ^>(6); fullnames[0] = L"Paul Bertrand Yamaguchi"; fullnames[1] = L"Ernestine Ngovayang"; fullnames[2] = L"Patricia L Katts"; fullnames[3] = L"Helene Mukoko"; fullnames[4] = L"Joan Ursula Hancock"; fullnames[5] = L"Arlette Mimosa"; } }; int main() { CStudentIdentifications ^ std = gcnew CStudentIdentifications; Console::WriteLine(L"Student Identification"); Console::WriteLine(L"Student ID: 39472"); Console::WriteLine(L"Full Name: {0}\n", std[39472]); Console::WriteLine(L"Student Identification"); Console::WriteLine(L"Full Name: Joan Ursula Hancock"); Console::WriteLine(L"Student ID: {0}\n", std[L"Joan Ursula Hancock"]); return 0; }
This would produce:
Student Identification Student ID: 39472 Full Name: Paul Bertrand Yamaguchi Student Identification Full Name: Joan Ursula Hancock Student ID: 28947 Press any key to continue . . .
An indexed property combines the features of an array and
those of a method that takes one or more parameters. As an array, an indexed
property can use one or more dimensions as we have seen so far. Borrowing the
features of a method, an indexed property can take one or more parameters and it
can return a value. Besides passing different types of parameters to various
indexed properties, you can create some of them that take
more than one parameter. Here is an example:
using namespace System; public ref class CCatalog { array<long> ^ nbrs; array<String ^> ^ names; array<double> ^ prices; public: // This property produces the name of an item, as a string, // if it is given the item #, as a number property String ^ default[long] { String ^ get(long nbr) { for (int i = 0; i < nbrs.Length; i++) if (nbr == nbrs[i]) return names[i]; return L"Unknown Item"; } } // This property produces the price of the item, as a number, // if it is given the item name and its number property double default[String ^, long] { double get(String ^ name, long nbr) { for (int i = 0; i < 5; i++) if ((nbr == nbrs[i]) && (name == names[i])) return prices[i]; return 0.00; } } CCatalog() { nbrs = gcnew array<long>(5); nbrs[0] = 273974; nbrs[1] = 539759; nbrs[2] = 710234; nbrs[3] = 220685; nbrs[4] = 192837; names = gcnew array<String ^>(5); names[0] = L"Women Double-faced wool coat"; names[1] = L"Men Cotton Polo Shirt"; names[2] = L"Children Cable-knit Sweater"; names[3] = L"Women Floral Silk Tank Blouse"; names[4] = L"Girls Jeans with Heart Belt"; prices = gcnew array<double>(5); prices[0] = 275.25; prices[1] = 18.75; prices[2] = 50.00; prices[3] = 65.35; prices[4] = 25.55; } }; int main() { CCatalog ^ cat = gcnew CCatalog; Console::WriteLine(L"Item Identification"); Console::WriteLine(L"Item #: 539759"); Console::WriteLine(L"Unit Price: {0}\n", cat[539759]); Console::WriteLine(L"Item Identification"); Console::WriteLine(L"Item #: 192837"); Console::WriteLine(L"Description: Girls Jeans with Heart Belt"); Console::WriteLine(L"Unit Price: {0}\n", cat["Girls Jeans with Heart Belt", 192837]); return 0; }
This would produce:
Item Identification Item #: 539759 Unit Price: Men Cotton Polo Shirt Item Identification Item #: 192837 Description: Girls Jeans with Heart Belt Unit Price: 25.55 Press any key to continue . . .
Read/Write Indexed Properties
|
Introduction
|
So far, we have purposely used indexed properties that only
produced a value. This type is used when you are (always) in charge of
specifying the values of the elements of the array: the only action you would
expect from the user is to retrieve the value of the property. This is referred
to as a read-only property. In some cases, you will use a property created by
someone else. You may want to specify the value of an element of the array. In
the same way, you may create an indexed property and you want the users of that
property to be able to specify the value of the array.
If you want an indexed property to be read/write, besides
the get accessor as we have been using it so far, you should also include a
set
accessor.
A Read/Write Property of a Primitive Type
|
To create a read/write indexed property, you must include
a set accessor for the property. When creating the set accessor,
pass two parameters. The first should be an integer type that would represent
the index of the item. The second parameter is used to represent the value that
will be assigned the the property. Here is an example of how this can be done:
public ref class CNumbers
{
array<double> ^ Nbrs;
public:
property double default[int]
{
double get(int i) { return Nbrs[i]; }
void set(int i, double value) { Nbrs[i] = value; }
}
CNumbers()
{
Nbrs = gcnew array<double>(5);
}
};
After creating the read/write property, you can assign its
values outside of the class. In other words, clients of the class can change the
values to its elements. Remember that the advantage of an indexed property is
that each element of the arrayed member variable can be accessed from the instance of the
class by directly applying the square brackets and the (appropriate) index to
it. Here is an example:
using namespace System; public ref class CNumbers { array<double> ^ Nbrs; public: property double default[int] { double get(int i) { return Nbrs[i]; } void set(int i, double value) { Nbrs[i] = value; } } CNumbers() { Nbrs = gcnew array<double>(5); } }; int main() { CNumbers ^ values = gcnew CNumbers; values[2] = 249.37094; for (int i = 0; i < 5; i++) Console::WriteLine(L"Number {0}: {1}", i + 1, values[i]); Console::WriteLine(); return 0; }
This would produce:
Number 1: 0 Number 2: 0 Number 3: 249.37094 Number 4: 0 Number 5: 0 Press any key to continue . . .
We saw that the index of a property could be a value other
than an integer-based. For example, we created an index that was a string type.
For such a property, if you make it read/write, you can assign its values
outside of the class. Here is an example of a read/write string-based
indexed property:
using namespace System; public ref class CPhilosopher { array<String ^> ^ phil; public: property String ^ default[int] { String ^ get(int i) { return phil[i]; } void set(int i, String ^ value) { phil[i] = value; } } CPhilosopher() { phil = gcnew array<String ^>(8); } }; int main() { CPhilosopher ^ thinker = gcnew CPhilosopher; thinker[5] = L"Stuart Rachels"; for(int i = 0; i < 8; i++) Console::WriteLine(L"Philosopher: {0}", thinker[i]); Console::WriteLine(); return 0; }
This would produce:
Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Stuart Rachels Philosopher: Philosopher: Press any key to continue . . .
The same rules would apply to a read/write indexed property
that can receive Boolean or double values.
No comments:
Post a Comment