Browse DevX
Sign up for e-mail newsletters from DevX


Book Excerpt: Essential Guide to Managed Extensions in C++ : Page 3

Managed Extensions for C++ are added to the Visual C++ .NET compiler to allow access to .NET Framework functionality. Visual C++ .NET is the only .NET language that can generate both native and managed code, and its rich set of features let you write managed applications for the .NET platform. This comprehensive guide to coding managed extensions for C++ was written by key members of the Visual C++ .NET compiler development teampeople who have spent most of their time implementing the language and educating others about managed C++. Read Chapter 9, ''Properties.''




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Implementing Property Access Methods
As you may have noticed, there are actually two get_Address methods defined in the class Database. One of them takes a student ID () as a parameter, whereas the other one takes String*, which demonstrates that property methods can be overloaded.

Overall, getters and setters are just regular functions. Not only can they be overloaded, they can also be declared virtual, pure virtual, or static. Property methods don't have to have the same access level. As in the example in the preceding section, Database::get_Address is public but Database::set_Address is protected. Furthermore, a property does not have to have both a getter and a setter; having either one is enough to define a property. If property methods are declared as static, no object is needed to access the property. This is similar to how you would access a static data member, as demonstrated here:

#using<mscorlib.dll> using namespace System; void main() { //Print current directory Console::WriteLine(Environment::CurrentDirectory ); }

This example uses the BCL class Environment, with a property called CurrentDirectory. Note that because the property is static, no instance of the class Environment is required. The same result could be achieved by calling the getter get_CurrentDirectory, which is a static member function:

void PrintDir() { //Print current directory Console::WriteLine(Environment::get_CurrentDirectory()); }

If you are concerned about performance overhead associated with a function call when using a property—don't worry. Property methods can be inlined, the same way as regular C++ member functions.

Parameters of Property Access Methods
Let's go back to our class Student example presented earlier and look closer at the getter and the setter. As you can see, get_Age takes no arguments and returns an int (one could argue that unsigned char, for instance, would be more appropriate, but let's ignore that for now).

The setter, set_Age, is a method that takes int as an argument. Note that the type of the setter parameter is the same as the return type of the getter—int. The MC++ compiler requires these two types to be identical. That understood, we could now say that the property Age has type int.

When it comes to indexed properties, keep in mind that to assign a value to the property you must pass it in the last argument of the setter. Let's look at the class Database in the example in the section "Scalar and Indexed Properties" earlier. What if you mistakenly defined the set_Address methods with the wrong order of parameters? For example:

#using <mscorlib.dll> using namespace System; __gc class Database { //... protected: __property void set_Address(String *address,int id ) { students_[id ]->Address =address; } __property void set_Address(String *address,String*name ) { int id =MapNameToId(name ); students_[id ]->Address =address; } };

In case of the first set_Address, you will get an error because the type of the setter's last argument () doesn't match the getter's return type ().

The second case is far more dangerous: the code will compile but produce wrong results. We will get back to this issue in the next section. For now, just remember that the last argument of the setter is used for passing a value to the property.

A well-designed property behaves exactly as if it were a public data member. Consider an example of using our class Student, defined earlier in this chapter:

void ResetAges(Student*student1,Student*student2) { return student1->Age =student2->Age =0; }

This would certainly work if Age were a public data member of class Student. However, this code gives an error:

'Student::set_Age ' ::cannot convert parameter 1 from 'void ' to 'int '

The problem lies in the return type of Student::set_Age , which is void. When properties are expanded into function calls, the compiler comes up with this:

void ResetAges(Student*student1,Student*student2) { return student1->set_Age(student2->set_Age(0)); }

This code doesn't work because student2->set_Age(0)returns void and there is no conversion from void to int. The solution? Define your setter as a method returning the property type or a reference to the property type:

__property int set_Age(int age){age_=age;return age_;}

Bear in mind, however, that this approach has certain performance implications—returning a variable doesn't come free. In some cases, the compiler can "optimize away" such overhead, but this is not always possible.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date