Properties Fundamentals

 

Introduction

The members of a class are divided in two main roles. The variables provide storage of data for an object; they also define the characteristics of an object. The methods perform related assignments of a class. Sometimes they receive requests from other objects or functions and provide the appropriate results that the other objects and functions are expecting. For this reason, the other objects and functions from outside the class don't need access to the member variables of an object; if they need anything, they would call a method of the class and let the object know "what they want".

To protect the data of a class, you can hide its member variables, after determining which member variables the other objects would not need access to. To hide a member variable, you can put it in a private section. Here is an example:

Header File: Rectangle.h
#pragma once

public ref class CRectangle
{
private:
    double len;
};
 
Source File: Rectangle.cpp
#include "Rectangle.h"

After making a member variable private, if you want outside classes or functions to access its value, you can create a public method that would act as an intermediary. On the other hand, if you want outside classes or functions to modify the value of that private member variable, you can define a public method that would "negotiate" this interaction. In traditional programming, these types of operations are taken care of by accessory methods.

Practical LearningPractical Learning: Introducing the Properties of a Class

  1. Start Microsoft Visual C++ 2008
  2. On the main menu, click File -> New -> Project...
  3. On the left side, make sure that Visual C++ is selected. In the Templates list, click CLR Empty Project
  4. In the Name box, replace the string with ElectroStore5 and click OK
  5. On the main menu, click Project -> Add New Item...
  6. To create a header file, in the Templates list, click Header File (.h)
  7. Set the Name to StoreItem and click Add
  8. Complete the file as follows:
    #pragma once
    using namespace System;
    
    namespace ElectronicsStore
    {
        public ref class CStoreItem
        {
        public:
            // An item whose characteristics are not (yet) known
            CStoreItem(void);
            // An item that is known by its make, model, and unit price
            CStoreItem(long itmNbr, String ^ make,
    		   String ^ model, double unitPrice);
            // An item that is known by its name and unit price
            CStoreItem(long itmNbr, String ^ name, double unitPrice);
            // An item completely defined
            CStoreItem(long itmNbr, __wchar_t category,
    			   String ^ make, String ^ model,
    			   double discountRate, double unitPrice);
            ~CStoreItem();
    
        private:
            long        nbr;
            __wchar_t ^ cat;
            String    ^ mk;
            String    ^ mdl;
    	String    ^ nm;
            double      discount;
            double      price;
    
        public:
            
        };
    }
  9. To create a source file, on the main menu, click Project -> Add New Item...
  10. In the Templates list, click C++ File (.h)
  11. Set the Name to StoreItem and press Enter
  12. Complete the file as follows:
     
    #include "StoreItem.h"
    using namespace System;
    
    namespace ElectronicsStore
    {
        CStoreItem::CStoreItem(void)
    	: nbr(0),
    	  cat(L'U'),
    	  mk(L"Unknown"),
    	  mdl(L"Unspecified"), 
    	  nm(L"N/A"),
    	  discount(0.00),
    	  price(0.00)
        {
        }
    
        CStoreItem::CStoreItem(long itmNbr, String ^ make,
    			   String ^ model, double unitPrice)
    	: nbr(itmNbr), 
    	  cat(L'U'),
    	  mk(make),
    	  mdl(model),
    	  nm(L"N/A"),
    	  discount(0.00),
    	  price(unitPrice)
        {
        }
        
        CStoreItem::CStoreItem(long itmNbr, String ^ name,
    				double unitPrice)
    	: nbr(itmNbr),
    	  cat(L'U'),
    	  mk(L"Unknown"),
    	  mdl(L"Unspecified"),
    	  nm(name),
    	  discount(0.00),
    	  price(unitPrice)
        {
        }
        
        CStoreItem::CStoreItem(long itmNbr, __wchar_t category,
    			   String ^ make, String ^ model,
    			   double discountRate, double unitPrice)
    	: nbr(itmNbr),
    	  cat(category),
    	  mk(make),
    	  mdl(model),
    	  discount(discountRate),
    	  price(unitPrice)
        {
        }
    
        CStoreItem::~CStoreItem()
        {
        }
    }
  13. To create one more source file, on the main menu, click Project -> Add New Item...
  14. In the Templates list, make sure C++ File (.cpp) is selected.
    Set the Name to Exercise and click Add
  15. Complete the file as follows:
    #include "StoreItem.h"
    
    using namespace System;
    using namespace ElectronicsStore;
    
    static void DescribeStoreItem(CStoreItem ^ %);
    
    int main()
    {
        String ^ strTitle = L"=-= Nearson Electonics =-=\n"
    		        L"******* Store Items ******";
        Console::WriteLine();
        return 0;
    }
  16. Execute the application to make sure it can compile
  17. Close the DOS window
  18. Reference Methods

    Because it cannot perform an assignment, a member variable of a class can only receive a value from the outside world. It can also be vulnerable to outside objects and functions. You can prevent this vulnerability by "hiding" the member variable in a private section. Because you may still want outside objects and functions to interact with the value held by a member variable, you can create an accessory method that corresponds to that variable. One way you can implement such a method is to make it return a reference.

    Like a regular function, a method of a class can be created to return a reference or a tracking reference. When creating the method, make sure you type the & or % operator on the left of its name. When implementing the method, in most cases, you can simply return a member variable of the class that is declared with the same data type as the one that the method would return. Here is an example:

    Header File: Rectangle.h
    #pragma once
    
    public ref class CRectangle
    {
    private:
    	double len;
    
    public:
    	double %Length();
    };
    Source File: Rectangle.cpp
    #include "Rectangle.h"
    
    double %CRectangle::Length()
    {
    	return len;
    }

    You may remember that a function can only be assigned to a variable. It cannot be assigned a value. In the same way, no value can be assigned to the name of a method. For example, the following code will not compile:

    public ref class Circle
    {
    private:
    	double Radius;
    public:
    	Circle(double rad) { Radius = rad; }
    	double Area() { return Radius * Radius * 3.14159; }
    };
    
    int main()
    {
    	Circle circ(24.55);
    	double a = 0.00;
    	circ.Area() = a;
    
    	return 0;
    }

    The exception to this rule is with reference methods. If a method returns a reference, it can be assigned a value. Here is an example:

    int main()
    {
    	CRectangle ^ rect = gcnew CRectangle;
    	
    	rect->Length() = 24.58;
    
    	ShowCharacteristics(rect);
    	Console::WriteLine();
    
    	return 0;
    }

    In the same way, a method that returns a reference can also have its value retrieved. Here is an example:

    Source File: Exercise.cpp
    #include "Rectangle.h"
    
    using namespace System;
    
    void ShowCharacteristics(CRectangle ^ %recto)
    {
    	Console::WriteLine(L"Rectangle Characteristics");
    	Console::WriteLine(L"Length:    {0}", recto->Length());
    }
    
    int main()
    {
    	CRectangle ^ rect = gcnew CRectangle;
    	
    	rect->Length() = 24.58;
    
    	ShowCharacteristics(rect);
    	Console::WriteLine();
    
    	return 0;
    }

    This would produce:

    Rectangle Characteristics
    Length:    24.58
    
    Press any key to continue . . .

    Notice that a reference method is assigned a value or a value is assigned to it. In the C++ jargon, this means that a reference method can be either an L-value (left value) or an R-value (right value) in an expression. As mentioned earlier, a regular member variable cannot validate or reject value because it cannot perform an assignment. Like the properties that we will see next, the ability for a reference method to be a left or right operand of an assignment makes it a valuable candidate to validate or reject a value that is meant for a member variable.

    A Property

    A method is an action that is performed to complement a class. It requires the mechanism of a function: some parentheses and optional arguments. If you declare a private member variable that must interact with the outside world, you must also implement different methods to accomplish different roles. One of the obstacles of a normal method is that it cannot be assigned a value, unless you create it as returning a reference. A property provides a solution to both problems in one object. To be able to play this role, a property must combine the functionalities of a member variable and that of a method. For this reason, there are strict rules you must follow to create a method.

    The primary syntax used to create a property is:

    modifier property type property_name;

    The modifier can be static (or virtual, which we will introduce in the next lessons). The property keyword is required. The property keyword is followed by a data type, which can be one of those we reviewed in Lesson 2. It can also be an enumeration. The data type is followed by the name of the property.

    Types of Properties

     

    Simple Properties

    A property is primarily a member variable of a class. To create one, you can simply precede the data type of a member variable with the property keyword. Here is an example:

    #pragma once
    
    public ref class CRectangle
    {
    private:
        double len;
        double hgt;
    
    public:
        CRectangle(double l, double h);
    
    public:
        property String ^ Name;
    };

    After creating a property, you can access it outside of its class like you would any member variable. You can first declare a variable of the class and then use the period operator to access the property. Here is an example:

    #include "Rectangle.h"
    
    using namespace System;
    
    void ShowCharacteristics(CRectangle %recto)
    {
        Console::WriteLine(L"Shape Characteristics");
        Console::WriteLine(L"Name: {0}", recto.Name);
    }
    
    int main()
    {
        CRectangle rect(24.58, -22.16);
    
        rect.Name = L"Rectangle";
        ShowCharacteristics(rect);
    
        Console::WriteLine();
        return 0;
    }

    Or you can create a handle to the class and use the arrow operator to access the property. Here is an example:

    #include "Rectangle.h"
    
    using namespace System;
    
    void ShowCharacteristics(CRectangle ^ %recto)
    {
        Console::WriteLine(L"Shape Characteristics");
        Console::WriteLine(L"Name: {0}", recto->Name);
    }
    
    int main()
    {
        CRectangle ^ rect = gcnew CRectangle(24.58, -22.16);
    
        rect->Name = L"Rectangle";
        ShowCharacteristics(rect);
    
        Console::WriteLine();
        return 0;
    }

    This would produce:

    Shape Characteristics
    Name: Rectangle
    
    Press any key to continue . . .

    Practical LearningPractical Learning: Creating Simple Properties

    1. Access the StoreItem.h file
    2. To create simple properties, declare the following variables:
      #pragma once
      using namespace System;
      
      namespace ElectronicsStore
      {
          public ref class CStoreItem
          {
          public:
              // An item whose characteristics are not (yet) known
              CStoreItem(void);
              // An item that is known by its make, model, and unit price
              CStoreItem(long itmNbr, String ^ make,
      		   String ^ model, double unitPrice);
              // An item that is known by its name and unit price
              CStoreItem(long itmNbr, String ^ name, double unitPrice);
              ~CStoreItem();
      
          private:
              long        nbr;
              __wchar_t ^ cat;
              String    ^ mk;
              String    ^ mdl;
      	    String    ^ nm;
              double      discount;
              double      price;
      
          public:
              property long        ItemNumber;
              property __wchar_t ^ Category;
              property String    ^ Make;
              property String    ^ Model;
              property String    ^ Name;
              property double      DiscountRate;
              property double      UnitPrice;
          };
      }
    3. Access the Exercise.cpp file
    4. To test the simple properties, change it as follows:
      #include "StoreItem.h"
      
      using namespace System;
      using namespace ElectronicsStore;
      
      static void DescribeStoreItem(CStoreItem ^ %);
      static void DescribeStoreItem(CStoreItem ^ %, const int);
      
      int main()
      {
          String ^ strTitle = L"=-= Nearson Electonics =-=\n"
      		        L"******* Store Items ******";
      
          CStoreItem ^ saleItem = gcnew CStoreItem();
      
          Console::WriteLine(L"==/==A store item with default values==/==");
          DescribeStoreItem(saleItem, 0);
          Console::WriteLine();
      
          Console::WriteLine(L"==/==A store item completely defined==/==");
          saleItem = gcnew CStoreItem();
          saleItem->ItemNumber = 513497;
          saleItem->Category   = L'T';
          saleItem->Make       = L"Uniden";
          saleItem->Model = L"8x8 Packet8 Broadband Internet Phone System";
          saleItem->DiscountRate = -10;
          saleItem->UnitPrice    =  -145.95;
          DescribeStoreItem(saleItem, 0);
      
          Console::WriteLine();
          return 0;
      }
      
      // This function is used when an item is specified by its make and model
      void DescribeStoreItem(CStoreItem ^ %item)
      {
          Console::WriteLine(L"Store Item Description");
          Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
          Console::WriteLine(L"Category:      {0}", item->Category);
          Console::WriteLine(L"Make           {0}", item->Make);
          Console::WriteLine(L"Model:         {0}", item->Model);
          Console::WriteLine(L"Name:          {0}", item->Name);
          Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
          Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
      }
      
      // This function is used when an item is specified by its name
      void DescribeStoreItem(CStoreItem ^ %item, const int)
      {
          Console::WriteLine(L"Store Item Description");
          Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
          Console::WriteLine(L"Category:      {0}", item->Category);
          Console::WriteLine(L"Make           {0}", item->Make);
          Console::WriteLine(L"Model:         {0}", item->Model);
          Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
          Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
      }
    5. Execute the application to test it. This would produce:
      ==/==A store item with default values==/==
      Store Item Description
      Item Number:   0
      Category:
      Make
      Model:
      Discount Rate: 0.00 %
      Unit Price:    $0.00
      
      ==/==A store item completely defined==/==
      Store Item Description
      Item Number:   513497
      Category:      T
      Make           Uniden
      Model:         8x8 Packet8 Broadband Internet Phone System
      Discount Rate: -1,000.00 %
      Unit Price:    ($145.95)
      
      Press any key to continue . . .
    6. Close the DOS window

    Read-Only Properties

    One of the roles of a property is to allow the other members of the class or the other class and functions of an application to find out what value the property is holding. Such a property is referred to as "getter". The formula to create a property that provides the value of its member variable is:

    modifier property type property_name
    {
          modifier type get();
    }

    Notice that the property is created like a namespace: it has a body and curly brackets but no parentheses like a function. In the body of the property, there is a type of method named get. This name is required. Because the property is meant to return a value, the get() method returns a data type. Because get() is a method, it must have a body delimited with curly brackets. Here is an example from our CRectangle class:

    public ref class CRectangle
    {
    private:
        double len;
        double hgt;
    
    public:
        property double Length
        {
    	double get() {}
        }
    };

    Use the body of the get method to implement the necessary behavior of the property getter. The simplest way consists of returning its corresponding private member variable. Here is an example:

    public ref class CRectangle
    {
    private:
        double len;
    
    public:
        property double Length
        {
    	double get() { return len; }
        }
    };

    When a property includes only a get() method, such a property is referred to as a read-only because the outside classes and functions can only retrieve the value of the property but they cannot change it. A classic example is the area of a rectangle. There is no need or reason for outside classes or functions to modify this value. They can only retrieve it if they need it. For this reason, you can create such a method as read-only. Here is an example:

    public ref class CRectangle
    {
    private:
    	double len;
    	double hgt;
    
    public:
    	CRectangle(double l, double h);
    
    public:
    	property double Length
    	{
    		double get() { return len; }
    	}
    
    	property double Area
    	{
    		double get()
    		{
    			return len * hgt;
    		}
    	}
    };

    After creating a property, you can access it like you would any member variable. You can first declare a variable of the class, a pointer to the class, or its handle, and use either the period or the arrow operator. Here is an example:

    using namespace System;
    
    public ref class CRectangle
    {
    private:
    	double len;
    	double hgt;
    
    public:
    	CRectangle();
    	CRectangle(double l, double h);
    
    public:
    	property double Length
    	{
    		double get() { return len; }
    	}
    
    	property double Perimeter
    	{
    		double get()
    		{
    			return 2 * (len + hgt);
    		}
    	}
    
    	property double Area
    	{
    		double get()
    		{
    			return len * hgt;
    		}
    	}
    };
    
    CRectangle::CRectangle()
        : len(0.00), hgt(0.00)
    {
    }
    
    CRectangle::CRectangle(double l, double h)
        : len(l), hgt(h)
    {
    }
    
    void ShowCharacteristics(CRectangle ^ %recto)
    {
    	Console::WriteLine(L"Rectangle Characteristics");
    	Console::WriteLine(L"Length:    {0}", recto->Length);
    	Console::WriteLine(L"Perimeter: {0}", recto->Perimeter);
    	Console::WriteLine(L"Area:      {0}", recto->Area);
    }
    
    int main()
    {
    	CRectangle ^ rect = gcnew CRectangle(24.58, -22.16);
    
    	ShowCharacteristics(rect);
    
    	Console::WriteLine();
    	return 0;
    }

    This would produce:

    Rectangle Characteristics
    Length:    24.58
    Perimeter: 4.84
    Area:      -544.6928
    
    Press any key to continue . . .

    In the same way, you can create as many read-only properties as you want.

    Notice that the perimeter of our rectangle appears to be less than the length. Furthermore, the area is negative. Both values don't make sense. A getter property doesn't have to directly produce the value of the member variable. It can use a mechanism to validate a value that its corresponding member variable is holding. If the value is admissible, you can use it. If the value is not acceptable, you can either reject it or provide an appropriate alternative.

    Practical LearningPractical Learning: Using Read-Only Properties of a Class

    1. Display the StoreItem.h header file
    2. To transform the simple properties into read-only, change the file as follows:
      #pragma once
      using namespace System;
      
      namespace ElectronicsStore
      {
          public ref class CStoreItem
          {
          public:
              // An item whose characteristics are not (yet) known
              CStoreItem(void);
              // An item that is known by its make, model, and unit price
              CStoreItem(long itmNbr, String ^ make,
      		   String ^ model, double unitPrice);
              // An item that is known by its name and unit price
              CStoreItem(long itmNbr, String ^ name, double unitPrice);
              // An item completely defined
              CStoreItem(long itmNbr, __wchar_t category,
      		   String ^ make, String ^ model,
      		   double discountRate, double unitPrice);
              ~CStoreItem();
      
          private:
              long        nbr;
              __wchar_t ^ cat;
              String    ^ mk;
              String    ^ mdl;
      	    String    ^ nm;
              double      discount;
              double      price;
      
          public:
              property long ItemNumber
              {
      		long get() { return nbr; }
      	}
      
              property __wchar_t ^ Category
              {
      		__wchar_t ^ get() { return cat; }
      	}
      
              property String ^ Make
              {
      		String ^ get() { return mk; }
      	}
      
              property String ^ Model
              {
      		String ^ get() { return mdl; }
      	}
      
              property String ^ Name
              {
      		String ^ get() { return nm; }
      	}
      
              property double DiscountRate
              {
      		double get() { return discount; }
      	}
      
              property double UnitPrice
              {
      		double get() { return price; }
      	}
      
          };
      }
    3. Execute the application to test it
    4. Notice that you receive many errors because of the assignments in the Exercise.cpp file
    5. Access the Exercise.cpp file and change it as follows:
       
      #include "StoreItem.h"
      
      using namespace System;
      using namespace ElectronicsStore;
      
      static void DescribeStoreItem(CStoreItem ^ %);
      static void DescribeStoreItem(CStoreItem ^ %, const int);
      
      int main()
      {
          String ^ strTitle = L"=-= Nearson Electonics =-=\n"
      		        L"******* Store Items ******";
      
          CStoreItem ^ saleItem = gcnew CStoreItem();
      
          Console::WriteLine(L"==/==A store item with default values==/==");
          DescribeStoreItem(saleItem, 0);
          Console::WriteLine();
      
          Console::WriteLine(L"==/==A store item completely defined==/==");
          saleItem = gcnew CStoreItem(513497, L'T', L"Uniden",
      		L"8x8 Packet8 Broadband Internet Phone System",
      		-10, -145.95);
          DescribeStoreItem(saleItem, 0);
      
          Console::WriteLine();
          return 0;
      }
      
      // This function is used when an item is specified by its make and model
      void DescribeStoreItem(CStoreItem ^ %item)
      {
          Console::WriteLine(L"Store Item Description");
          Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
          Console::WriteLine(L"Category:      {0}", item->Category);
          Console::WriteLine(L"Make           {0}", item->Make);
          Console::WriteLine(L"Model:         {0}", item->Model);
          Console::WriteLine(L"Name:          {0}", item->Name);
          Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
          Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
      }
      
      // This function is used when an item is specified by its name
      void DescribeStoreItem(CStoreItem ^ %item, const int)
      {
          Console::WriteLine(L"Store Item Description");
          Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
          Console::WriteLine(L"Category:      {0}", item->Category);
          Console::WriteLine(L"Make           {0}", item->Make);
          Console::WriteLine(L"Model:         {0}", item->Model);
          Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
          Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
      }
    6. Execute the application again
    7. Close the DOS window
    8. Write-Only Properties

      As mentioned previously, if you create a private member variable, the outside classes and functions cannot access it to influence its value. If you still want these other classes and functions to modify the value of the member variable, you can create a property to stand in the middle. The outside classes and functions can then submit a value to the property, and the property would be in charge of assigning it to the corresponding member variable. The formula to create such a property is:

      modifier property type property_name
      {
            modifier void set(type);
      }

      This type of property is used to receive values for a member variable. Because it doesn't return a value, it is created as void. The method that actually handles the "transaction" is named set. The value that is submitted to the property is passed as an argument to the set() method. Because set is a method, it must have a body. Here is an example:

      public ref class CRectangle
      {
      private:
      	double hgt;
      
      public:
      	property double Height
      	{
      		void set(double h) { }
      	}
      };

      In the body of the set() method, define the necessary behavior of the property. At a minimum, you can assign the argument to the corresponding member variable. Here is an example:

      public ref class CRectangle
      {
      private:
      	double hgt;
      
      public:
      	property double Height
      	{
      		void set(double h) { hgt = h; }
      	}
      };

      Once again, to access the property from an external object or function, you can use the appropriate operator (. or ->) as if it were a member variable. Here is an example:

      using namespace System;
      
      public ref class CRectangle
      {
      private:
      	double len;
      	double hgt;
      
      public:
      	CRectangle();
      	CRectangle(double l, double h);
      
      public:
      	property double Length
      	{
      		double get() { return len; }
      	}
      
      	property double Height
      	{
      		void set(double h) { hgt = h; }
      	}
      
      	property double Perimeter
      	{
      		double get()
      		{
      			return 2 * (len + hgt);
      		}
      	}
      
      	property double Area
      	{
      		double get()
      		{
      			return len * hgt;
      		}
      	}
      };
      
      CRectangle::CRectangle()
          : len(0.00), hgt(0.00)
      {
      }
      
      CRectangle::CRectangle(double l, double h)
          : len(l), hgt(h)
      {
      }
      
      void ShowCharacteristics(CRectangle ^ %recto)
      {
      	Console::WriteLine(L"Rectangle Characteristics");
      	Console::WriteLine(L"Length:    {0}", recto->Length);
      	Console::WriteLine(L"Perimeter: {0}", recto->Perimeter);
      	Console::WriteLine(L"Area:      {0}", recto->Area);
      }
      
      int main()
      {
      	CRectangle ^ rect = gcnew CRectangle(24.58, 22.16);
      
      	rect->Height = 35.64;
      	ShowCharacteristics(rect);
      
      	Console::WriteLine();
      	return 0;
      }

      This would produce:

      Rectangle Characteristics
      Length:    24.58
      Perimeter: 22.12
      Area:      876.0312
      
      Press any key to continue . . .

      Read/Write Properties

      We have seen that a property provides a valuable relationship between a private member variable of a class and the outside world. As such, it can both receive values for the member variable and provide values to the outside world. This means that a property can be meant to both read from and write to its corresponding member variable. Such a proeprty is referred to as read/write.

      To create a read/write property, you must implement both the get() and the set() methods of the property. When a property is read/write, its set() method can be used to validate the values that are submitted to the property. The get() method can then be used to present the current value of the property to the external classes and functions. It is important to note that the other members of the class can also access the property. Here are examples of read/write properties:

      Header File: Rectangle.h
      #pragma once
      
      using namespace System;
      
      public ref class CRectangle
      {
      private:
      	double len;
      	double hgt;
      
      public:
      	property String ^ Name;
      
          property double Length
          {
          	double get() { return len; }
      
      	void set(double L)
      	{
      		len = L;
      	}
          }
      
          property double Height
          {
      	double get() { return hgt; }
      
      	void set(double h)
      	{
      		hgt = h;
      	}
          }
      
          property double Perimeter
          {
      	double get()
      	{
      		return 2 * (Length + Height);
      	}
          }
      
          property double Area
          {
      	double get()
      	{
      		return Length * Height;
      	}
          }
      };
      Source File: Rectangle.cpp
      #include "Rectangle.h"
      Source File: Exercise.cpp
      #include "Rectangle.h"
      
      using namespace System;
      
      CRectangle ^ CreateShape()
      {
      	CRectangle ^ R = gcnew CRectangle;
      
      	R->Name = L"Rectangle";
      	R->Length = 42.06;
      	R->Height = 27.92;
      	return R;
      }
      
      void ShowCharacteristics(CRectangle ^ %recto)
      {
      	Console::WriteLine(L"Shape Characteristics");
      	Console::WriteLine(L"Name:      {0}", recto->Name);
      	Console::WriteLine(L"Length:    {0}", recto->Length);
      	Console::WriteLine(L"Perimeter: {0}", recto->Perimeter);
      	Console::WriteLine(L"Area:      {0}", recto->Area);
      }
      
      int main()
      {
      	CRectangle ^ rect = CreateShape();
      
      	ShowCharacteristics(rect);
      
      	Console::WriteLine();
      	return 0;
      }

      This would produce:

      Shape Characteristics
      Name:      Rectangle
      Length:    42.06
      Perimeter: 139.96
      Area:      1174.3152
      
      Press any key to continue . . .

      Practical LearningPractical Learning: Using Read/Write Properties of a Class

      1. Access the StoreItem.h header file
      2. To complete the properties of the class, change the file as follows:
        #pragma once
        using namespace System;
        
        namespace ElectronicsStore
        {
            public ref class CStoreItem
            {
            public:
                // An item whose characteristics are not (yet) known
                CStoreItem(void);
                // An item that is known by its make, model, and unit price
                CStoreItem(long itmNbr, String ^ make,
        		   String ^ model, double unitPrice);
                // An item that is known by its name and unit price
                CStoreItem(long itmNbr, String ^ name, double unitPrice);
                // An item completely defined
                CStoreItem(long itmNbr, __wchar_t category,
        	           String ^ make, String ^ model,
        		   double discountRate, double unitPrice);
                ~CStoreItem();
        
            private:
                long        nbr;
                __wchar_t ^ cat;
                String    ^ mk;
                String    ^ mdl;
        	String    ^ nm;
                double      discount;
                double      price;
        
            public:
                property long ItemNumber
                {
                    long get() { return nbr; }
        	    void set(long n) { this->nbr = n; }
        	}
        
                property __wchar_t ^ Category
                {
                    __wchar_t ^ get() { return cat; }
        	    void set(__wchar_t ^ n) { this->cat = n; }
        	}
        
                property String ^ Make
                {
        	    String ^ get() { return mk; }
        	    void set(String ^ m) { this->mk = m; }
        	}
        
                property String ^ Model
                {
        	    String ^ get() { return mdl; }
        	    void set(String ^ m) { this->mdl = m; }
        	}
        
                property String ^ Name
                {
                    String ^ get() { return nm; }
        	    void set(String ^ n) { this->nm = n; }
        	}
        
                property double DiscountRate
                {
        	    double get() { return discount; }
        	    void set(double d) { this->discount = d; }
        	}
        
                property double UnitPrice
                {
        	    double get() { return price; }
        	    void set(double p) { this->price = p; }
        	}
            };
        }
      3. Access the Exercise.cpp file and change it as follows:
        #include "StoreItem.h"
        
        using namespace System;
        using namespace ElectronicsStore;
        
        CStoreItem ^ CreateStoreItem();
        static void DescribeStoreItem(CStoreItem ^ %);
        static void DescribeStoreItem(CStoreItem ^ %, const int);
        
        int main()
        {
            String ^ strTitle = L"=-= Nearson Electonics =-=\n"
        		        L"******* Store Items ******";
        
            CStoreItem ^ saleItem = CreateStoreItem();
        
            Console::WriteLine(L"");
            DescribeStoreItem(saleItem, 0);
        
            Console::WriteLine();
            return 0;
        }
        
        CStoreItem ^ CreateStoreItem()
        {
            long        number;
            __wchar_t ^ category;
            String    ^ make;
            String    ^ model;
            double      discount;
            double      price;
        
            Console::WriteLine(L"To create a store item, enter its information");
            Console::Write(L"Item Number: ");
            number = long::Parse(Console::ReadLine());
            Console::WriteLine(L"Category");
            Console::WriteLine(L"A - Audio Cables");
            Console::WriteLine(L"B - Instructional and Tutorials (Books)");
            Console::WriteLine(L"C - Cell Phones and Accessories");
            Console::WriteLine(L"D - Bags and Cases");
            Console::WriteLine(L"H - Headphones");
            Console::WriteLine(L"I - Instructional and Tutorials (VHS & DVD)");
            Console::WriteLine(L"M - Digital Cameras");
            Console::WriteLine(L"O - Cables and Connectors");
            Console::WriteLine(L"P - PDAs and Accessories");
            Console::WriteLine(L"T - Telephones and Accessories");
            Console::WriteLine(L"S - Surge Protector");
            Console::WriteLine(L"V - TVs and Videos");
            Console::Write(L"Your Choice? ");
            category = __wchar_t::Parse(Console::ReadLine());
            Console::Write(L"Make         ");
            make = Console::ReadLine();
            Console::Write(L"Model:       ");
            model = Console::ReadLine();
            Console::Write(L"Discount Applied (Enter 0 to 100, 0 if no discount): ");
            discount = double::Parse(Console::ReadLine());
            Console::Write(L"Unit Price:  ");
            price = double::Parse(Console::ReadLine());
        
            CStoreItem ^ sItem = gcnew CStoreItem;
            sItem->ItemNumber   = number;
            sItem->Category     = category;
            sItem->Make         = make;
            sItem->Model        = model;
            sItem->DiscountRate = discount;
            sItem->UnitPrice    = price;
        
            return sItem;
        }
        
        // This function is used when an item is specified by its make and model
        void DescribeStoreItem(CStoreItem ^ %item)
        {
            Console::WriteLine(L"Store Item Description");
            Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
            Console::WriteLine(L"Category:      {0}", item->Category);
            Console::WriteLine(L"Make           {0}", item->Make);
            Console::WriteLine(L"Model:         {0}", item->Model);
            Console::WriteLine(L"Name:          {0}", item->Name);
            Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
            Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
        }
        
        // This function is used when an item is specified by its name
        void DescribeStoreItem(CStoreItem ^ %item, const int)
        {
            Console::WriteLine(L"Store Item Description");
            Console::WriteLine(L"Item Number:   {0}", item->ItemNumber);
            Console::WriteLine(L"Category:      {0}", item->Category);
            Console::WriteLine(L"Make           {0}", item->Make);
            Console::WriteLine(L"Model:         {0}", item->Model);
            Console::WriteLine(L"Discount Rate: {0:P}", item->DiscountRate);
            Console::WriteLine(L"Unit Price:    {0:C}", item->UnitPrice);
        }
      4. Execute the application to test it. Here is an example:
         
        To create a store item, enter its information
        Item Number: 666802
        Category
        A - Audio Cables
        B - Instructional and Tutorials (Books)
        C - Cell Phones and Accessories
        D - Bags and Cases
        H - Headphones
        I - Instructional and Tutorials (VHS & DVD)
        M - Digital Cameras
        O - Cables and Connectors
        P - PDAs and Accessories
        T - Telephones and Accessories
        S - Surge Protector
        V - TVs and Videos
        Your Choice? V
        Make         Maxent
        Model:       MX-42VM11
        Discount Applied (Enter 0 to 100, 0 if no discount): 5
        Unit Price:  1250.50
        
        Store Item Description
        Item Number:   666802
        Category:      V
        Make           Maxent
        Model:         MX-42VM11
        Discount Rate: 500.00 %
        Unit Price:    $1,250.50
        
        Press any key to continue . . .
      5. Close the DOS window

      Other Techniques of Implementing Properties

       

      Static Properties

      Like a regular member variable, a property van be created as static. To do this, precede its name with the static keyword. A static property can implement only the behavior of a static member variable. Here is an example:

      public ref class CComputerInventory
      {
      private:
          static String ^ name;
      
      public:
          property static String ^ ComputerName
          {
      	String ^ get() { return name; }
      	void set(String ^ nm) { name = nm; }
          }
      };

      After creating a static property, you can access it outside using the . or the -> operators. Because it is static, you can also access it using the :: operator applied to the name of the class. Here are examples:

      using namespace System;
      
      public ref class CComputerInventory
      {
      private:
          static String ^ name;
          static String ^ mnUser;
      
      public:
          property static String ^ ComputerName
          {
      	String ^ get() { return name; }
      	void set(String ^ nm) { name = nm; }
          }
      
          property static String ^ MainUser
          {
      	String ^ get() { return mnUser; }
      	void set(String ^ user) { mnUser = user; }
          }
      };
      
      void ListComputer(CComputerInventory ^ cInv)
      {
          Console::WriteLine(L"Computer Inventory");
          Console::WriteLine(L"Computer Name: {0}", cInv->ComputerName);
          Console::WriteLine(L"Main User:     {0}", cInv->MainUser);
      }
      
      int main()
      {
          CComputerInventory ^ inv = gcnew CComputerInventory;
          CComputerInventory::ComputerName = L"CNTLWKS228";
          CComputerInventory::MainUser     = L"Gertrude Monay";
      
          ListComputer(inv);
      
          Console::WriteLine();
          return 0;
      }

      This would produce:

      Computer Inventory
      Computer Name: CNTLWKS228
      Main User:     Gertrude Monay
      
      Press any key to continue . . .

      A Class Property

      As done for a primitive type, you can create a property that is based on a class. If the class is managed, type the ^ operator between the class's name and its property name. We will see an example in Lesson 16.

      A Property as a Handle

      All of the properties we have created so far were of primitive types in the stack. You can also create a property in the managed heap. To do this, type the ^ operator between its data type and its name.

      Inheriting a Property

      When you derive a class from another, the new class inherits the (public) properties of the parent class. This is one of the most valuable characteristics of properties.


      Previous Copyright © 2006-2025, FunctionX 14 October 2008, 10:12 Next