< C++ .NET Arrays & Collections 10 | Main | C++ .NET Properties 2 >


 

 

Properties 1

get me and set me!

 

 

What we have in this page?

 

  1. Introduction

  2. What Are Properties?

  3. The Two Kinds of Properties

  4. __property keyword

  5. Property Declaration of the managed extension for C++ and new managed C++

-----------Next---------------------

  1. More on property keyword

  2. Rules for Constructing Scalar Properties

  3. Implementing Scalar Properties

  4. Errors in Properties

  5. Read-Only and Write-Only Properties

  6. Implementing Indexed Properties

  7. The Bank Example

  8. Implementing the Bank Class

  9. Adding the Account Class

  10. Creating Account Class Properties

  11. Adding Accounts to the Bank Class

  12. Implementing the Add and Remove Methods

  13. Implementing an Indexed Property to Retrieve Accounts

  14. More On Indexed Properties

  15. Declaring and Using Static Properties

  16. Declaring and Using Virtual Properties

  17. Using Multidimensional Properties

  18. Overloading Property Accessor Methods

  19. Declaring Abstract and Sealed Properties

  20. Quick Reference

 

 

Introduction

 

Properties have been available in some programming languages such as Microsoft Visual Basic for some time, but the .NET Framework has added support for them into Microsoft (Machine) Symbol Intermediate Language (MSIL) so that they can easily be implemented in any .NET programming language. You’ll see in this module that properties can often lead to a more natural style of programming without sacrificing robustness or violating principles of object-oriented programming.

 

What Are Properties?

 

A long-accepted tenet of object-oriented programming is that it’s a bad idea to give users direct access to the data members that make up your classes. There are two main reasons for this:

  1. If users directly access data members, they’re required to know about the implementation of the class, and that might limit your ability to modify the implementation later.

  2. Users of your classes might deliberately or accidentally corrupt the data in objects by using inappropriate values, possibly leading to program failures or other undesirable results.

 

As a result, it’s recommended that you hide data members, making them private and giving indirect access to them by using member functions. In traditional C++, indirect access has often been implemented using get and set members so that a data member named date might be accessed using a pair of member functions named set_date and get_date. This method works fine, but client code always has to call the get and set functions directly. Properties in the .NET Framework give you a way to implement a virtual data member for a class. You implement the get and set properties, and the compiler converts them into calls to the get or set method as appropriate. Consider the following codes:

MyClass^ pmc = gcnew MyClass;

// calls pmc->set_Name("fred")...

pmc->Name = "fred";

// calls pmc->get_Name()...

s = pmc->Name;

It appears to the user that MyClass has a real data member named Name, and the property can be used in exactly the same way as a real data member. If you’ve programmed in Visual Basic, the idea of implementing properties using the get, set, and let methods should be familiar to you. In the .NET Framework, properties can be created and used in any .NET language, so you can create a class in Visual Basic .Net and still use its properties in a C++ .Net program, and vice versa.

 

 

 

 

The Two Kinds of Properties

 

Two kinds of properties are supported by the Managed Extension for C++ and new C++ .Net:

  1. Scalar properties - A scalar property gives access to a single value by using get and set methods. For example, a Name property would implement the get_Name and set_Name (managed C++) functions to give access to the underlying name data. It’s important to note that a property doesn’t have to represent a simple data member of the managed class. A property can represent derived values. For example, if a class has a date_of_birth member, it would be possible to implement an age property that calculates the age. Properties can also represent far more complex values, which might involve using data from other sources, such as searching databases or accessing URLs.

  2. Indexed properties - An indexed property allows a property to be accessed as if it’s an array, using the traditional C++ square bracket ([]) notation. If you’ve ever come across the overloaded [ ] operator in traditional C++, you’ll find that indexed properties provide similar functionality, but you don’t have to code the operator overload yourself. Indexed properties still use the get and set methods for implementation, and the compiler automatically generates the required code so that clients can use the square bracket notation. So, if the compiler sees a property that can be implemented as an indexed property, it will automatically generate the code. The next sections in this module demonstrate how to implement both scalar and indexed properties. Take note that the old Managed Extension for C++ and the new managed C++ syntax included the discussion.

 

__property keyword

 

This section applies only to version 1 of Managed Extensions for C++. This syntax should only be used to maintain version 1 code (VC++ 2002 and VC++ . Net 2003). Use property keyword for the equivalent functionality in the new managed C++ syntax (VC++ 2005) and explained in the next section. __property keyword declares either a scalar or indexed property for the managed class. The syntax is:

__property function-declarator

The __property keyword introduces the declaration of a property and can appear in a class, interface, or value type. A property can have a getter function (get, read only), a setter function (set, write only), or both (get/set, read-write). A property name cannot match the name of the managed class containing it. The return type of the getter function must match the type of the last parameter of a corresponding setter function. For example, notice the int return type of the getter and parameter of the setter function in the following code.

__property int get_Size() { return m_size; }

__property void set_Size(int value) { m_size = value; }

In the following example, a scalar property (Size) is added to the MyClass declaration. The property is then implicitly set and retrieved using the get_Size and set_Size functions.

// __property keyword

// compile with: /clr:oldSyntax

#include "stdafx.h"

 

using namespace System;

 

__gc class MyClass

{

   public:

      // constructor

      MyClass() : m_size(0) {}

      // get value...

      __property int get_Size() { return m_size; }

      // set value...

      __property void set_Size(int value) { m_size = value; }

      // compiler generates pseudo data member called Size

   protected:

      int m_size;

};

 

int main()

{

   MyClass* class1 = new MyClass;

   int curValue;

   Console::Write("Default value, class1->Size = ");

   Console::WriteLine(class1->Size);

   // calls the set_Size function with value == 4

   class1->Size = 4;

   Console::Write("New value, class1->Size = ");

   Console::WriteLine(class1->Size);

   // calls the get_Size function

   curValue = class1->Size;

   Console::Write("Get current value, class1->Size = ");

   Console::WriteLine(curValue);

   return 0;

}

 

Output:

 

 

 

 

A program example - a scalar property (Size) is added to the MyClass declaration. The property is then implicitly set and retrieved using the get_Size and set_Size functions

 

Property Declaration of the managed extension for C++ and new managed C++

 

The way to declare a property in a managed class has changed from Managed Extensions for C++ to Visual C++ 2005. In the Managed Extensions design, each set or get property accessor is specified as an independent member function. As explained before, the declaration of each method is prefixed with the __property keyword. The method name begins with either set_ or get_ followed by the actual name of the property (as visible to the user). Thus, a Vector providing an x coordinate get property would name it get_x and the user would invoke it as x. This naming convention and separate specification of methods actually reflects the underlying runtime implementation of the property. For example, here is our Vector with a set of coordinate properties.

public __gc __sealed class Vector

{

   public:

     __property double get_x(){ return _x; }

     __property double get_y(){ return _y; }

     __property double get_z(){ return _z; }

     __property void set_x( double newx ){ _x = newx; }

     __property void set_y( double newy ){ _y = newy; }

     __property void set_z( double newz ){ _z = newz; }

};

This was found to be confusing because it spreads out the functionality associated with a property and requires the user to lexically unify the associated sets and gets. Moreover, it is lexically verbose and feels inelegant. In the new syntax, which is more like that of C#, the property keyword is followed by the type of the property and its bare name. The set and get access methods are placed within a block following the property name. Note that unlike C#, the signature of the access method is specified. For example, here is the code example above translated into the new syntax.

public ref class Vector sealed

{

   public:

      property double x

      {

        double get() { return _x; }

        void set( double newx ) { _x = newx; }

      } // Note: no semi-colon

};

If the access methods of the property reflect distinct access levels such as a public get and a private or protected set, an explicit access label can be specified. By default, the access level of the property reflects that of the enclosing access level. For example, in the above definition of Vector, both the get and set methods are public. To make the set method protected or private, the definition would be revised as follows:

public ref class Vector sealed

{

   public:

     property double x

     {

        double get() { return _x; }

        private:

            void set( double newx ) { _x = newx; }

     } // note: extent of private end here...

     // note: dot is back to the public method of Vector

     double dot( const Vector^ wv );

     // etc.

};

 

 

 

 

The extent of an access keyword within a property extends until either the closing brace of the property or the specification of an additional access keyword. It does not extend beyond the definition of the property to the enclosing access level within which the property is defined. In the above declaration, for example, Vector::dot() is a public member function. Writing the set/get properties for the three Vector coordinates as in the given example is a bit tedious given the canned nature of the implementation:

 

  1. Declare a private state member of the appropriate type,

  2. Return it when the user wishes to get its value, and

  3. Set it to whatever new value the user wishes to assign.

 

In the new syntax, a shorthand property syntax is available which automates this usage pattern as shown below:

public ref class Vector sealed

{

   public:

     // equivalent shorthand property syntax

     property double x;

     property double y;

     property double z;

};

The interesting side-effect of the shorthand property syntax is that while the backstage state member is automatically generated by the compiler, it is not accessible within the class except through the set/get accessors. Talk about the strict enforcement of data hiding!

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

 

 


 

< C++ .NET Arrays & Collections 10 | Main | C++ .NET Properties 2 >