How Properties Work
When you define a property by declaring a getter or a setter, the MC++ compiler "pretends" a data member is defined. This data member is called a
pseudo member because it doesn't actually exist. The compiler replaces the pseudo member in your code by a call to the appropriate method which, depending on the context, is either the getter or the setter:
#using <mscorlib.dll>
__gc class MyArray
{
//...
public:
//...
__property int get_Length();
__property void set_Length(int);
};
void IncrementLength(MyArray*pArray )
{
int nLen =pArray->Length;//calls pArray->get_Length();
pArray->Length =nLen +1;//calls pArray->set_Length(nLen +1);
}
Remember, we warned you in the last section that the value of the property must be passed in the last argument of the setter. Now it's time to shed some light on this situation. Here is how the compiler generates the function call for the setter: given an indexed property Address, the compiler will convert the expression
pDB->Address [S "John Smith "] ==S "Seattle ";
into
pDB->set_Address(S "John Smith ",S "Seattle ");
passing the value from the right side of the assignment in a last argument of the setter. That's why if this last argument expects anything else other than the new value of the property, you will not get the result you want.
What if you want to increment a property using operator++? You can do that as follows:
void IncrementLength2(MyArray*pArray )
{
++pArray->Length;
//compiler generates:
//pArray->set_Length(pArray->get_Length()+1);
pArray->Length++;
//compiler generates:
//int tmp;tmp =pArray->get_Length(),
//pArray->set_Length(tmp +1),tmp;
}
As in unmanaged C++, the post-increment operator is less efficient than the pre-increment operatorit requires a temporary variable to hold the value of the property before the increment. Hence this advice: where you can, consider using a pre-increment operator instead of a post-increment operator.
What You Cannot Do with Properties
As we said earlier, a good property behaves like a data member. Is there anything you can do with a data member but not with a property? Unfortunately, yes. Let's recall the earlier example with class Student. Consider the following:
#using <mscorlib.dll>
__gc class Student
{
int age_;
//...
public:
//...
__property int get_Age(){return age_;}
__property void set_Age(int age){age_=age;}
void Birthday();
};
void IncrementAge(int*pAge )
{
(*pAge)++;
}
void Student::Birthday()
{
IncrementAge(&Age );//error!
}
With what you now know about properties, it should come as no surprise that this code won't work. Still wondering why? Look at the call to IncrementAgethe function expects a parameter of type int*, but the property, Age, is provided instead. What can the compiler do? The pseudo member Age can be replaced with either get_Age or set_Age , neither of which would yield the desired result. That's why
taking address of a property is illegaland results in a compile-time error.
There is also one restriction to overloading property methods. Examine the following code:
#using <mscorlib.dll>
using namespace System;
__gc class Product
{
//...
};
__gc class Inventory
{
//...
public:
//...
__property int get_ItemsSold(int ProductID);
__property void set_ItemsSold(int ProductID,int value);
__property int get_ItemsSold()__gc [];*///error!
};
void SellProduct(Inventory*pInventory,int ProductID )
{
pInventory->ItemsSold [ProductID ]++;
}
As you can see, the method get_ItemsSold is overloaded: the first function takes one argument (), and the other one takes no arguments but returns a managed array. Now we have an ambiguity problem in the function SellProduct: how do you convert the property ItemsSold into a getter/setter function call? It is impossible to determine from the context whether either of the methods int get_ItemsSold(int)or int get_ItemsSold()__gc []should be called. So, what we want you to take away from this is
an array property declaration shall not overload an indexed property.
Summary
As this chapter has shown, managed properties are easy to use because the syntax for defining them is much simpler than that of regular C++ properties. Being syntactic sugar for function calls, properties behave like data members, making code that uses them cleaner and easier to understand.
In the next chapter, we will dive into another advanced topic of MC++operators. Like properties, operators provide a more natural way of coding by hiding function calls "under the hood." You will see how to define and use operators and user-defined conversions for value types as well as gc classes.
Reproduced from the Essential Guide to Managed Extensions for C++, by permission of Apress. ISBN 1-893115-28-3, copyright 2002. All rights reserved.