Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 35.  Properties


35.5. Static Properties

As was observed at the start of this chapter, even those compilers that support properties as an extension do not provide class (static) properties. So even if you don't need to use the templates discussed in the intervening sections, you may still need to use the following techniques.

As with instance properties, static properties come in field and/or method flavors.

35.5.1 Static Field Properties

Implementing static field properties can be done in exactly the same way as, for instance, field properties, using the field_property_get/set templates, as in:

Listing 35.26.


// SocketBuffer.h


class SocketBuffer


{


// Construction


public:


  SocketBuffer(. . . )


  {


    ++NumInstances.m_value; // Note: not thread-safe


  }


// Properties


public:


  static field_property_get<int, int>   NumInstances;


  . . .


};





// SocketBuffer.cpp


/* static */ field_property_get<int, int>    SocketBuffer::NumInstances(0);



This is used just as any other static field would be:



void monitor_proc(. . .)


{


  int bufferCount = SocketBuffer::NumInstances;


  . . .


}



35.5.2 Internal Static Method Properties

The instance method property mechanisms do not transfer to static method properties, since a static method property clearly cannot operate on an instance. Thankfully, this results in much simplified definitions.

I'm only going to show you the read/write versions, as the ground's been pretty much covered in previous sections. The internal version looks like:

Listing 35.27.


template< typename V


        , typename RG


        , typename RS


        , typename C


        , RG (*PFnGet)(void)


        , void (*PFnSet)(RS )


        >


class static_method_property_getset


{


  . . .


// Accessors


public:


  operator RG() const


  {


    return (*PFnGet)();


  }


  static_method_property_getset &operator =(RS value)


  {


    (*PFnSet)(value);


    return *this;


  }


// Members


private:


  V m_value;


};



We might use an internal static method property in the Date class to count the number of instances created, as in:

Listing 35.28.


class Date


{


public:


  Date(Date const &rhs)


    : m_time(rhs.m_time)


  {


    ++InstanceCount.m_value; // Note: not thread-safe


  }


public:


  static int get_InstanceCount()


  {


    return InstanceCount.m_value;


  }


public:


  static static_method_property_get<int, int, Date, &get_InstanceCount>   InstanceCount;


  . . .


};



Since the property is static, it needs to be defined:



static_method_property_get<int


                        ,  int


                        ,   Date


                        ,   &Date::get_InstanceCount


                        >       Date::InstanceCount;



The constructors are public, since it has to be used at file scope. Since you are the one who'll be calling the constructor for the properties of your containing class, this doesn't represent any lack of security. The full qualification of the method name is mandatory, since it's outside the context of the class definition.

Because we're not concerned about the size of static properties, the only advantage to using internal method properties over field properties is the opportunity for validation and translation of the actual field to and from the client code.

35.5.3 External Static Method Properties

When we don't need internal fields, we get the simplest of all the method properties. Again, I'm only showing the read/write version for brevity:

Listing 35.29.


template< typename RG


        , typename RS


        , RG (*PFnGet)(void)


        , void (*PFnSet)(RS )


        >


class static_method_property_getset_external


{


// Accessors


public:


  operator RG() const


  {


    return (*PFnGet)();


  }


  static_method_property_getset_external &operator =(RS value)


  {


    (*PFnSet)(value);


    return *this;


  }


};



static_method_property_get_external and static_method_property_set_external correspond to the read and write two halves of this type's implementation. Now we can at last define the Now property for Date:

Listing 35.30.


class Date


{


public:


  static Date get_Now()


  {


    return Date(time(NULL));


  }


public:


  static static_method_property_get_external<Date, &get_Now>  Now;


  . . .


};





static_method_property_get_external<Date, &get_Now>   Date::Now;



and would be used as follows:



Date  date = Date::Now;



With both the static method properties I've shown, I've not used macros, since they were not necessitated by any offset functions. However, for consistency you may wish to use them.


      Previous section   Next section