Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 4.  Data Encapsulation and Value Types


4.5. Encapsulated Types

POD open value types are fragile types, and their usefulness is limited to circumstances in which using a higher concept is demonstrably damaging to other requirements, such as performance, language-interoperability, or coupling. It is evident that most types are not useful and/or robust until they correspond at least to our next level: the encapsulated type. (Note that this definition can equally be applied to entity types.)

Definition: Encapsulated types provide access to, and manipulation of, instance state via a robust public interface, and client code should not, and need not, have access to the internal member state of instances of such types. Encapsulated types provide a notionally complete separation between logical and physical state.


Encapsulated types will generally hide the implementation details to a greater (usually complete) and, importantly, safe degree, and provide methods to safely access the representation of the value. For example, the uinteger64's lowerVal and upperVal members would be manipulated by Add(), Assign(), and similar methods on the class. And because methods are used to arbitrate access to, and manipulation of, the instance internal state, class invariants (section 1.3) can be enforced, significantly improving code quality.

Types may also provide additional methods so that client code will not have to hand-code common or expected operations. Unfortunately, this can be an open set of possibilities, even when we are being good citizens and maintaining orthogonality. This can be ameliorated by preferring free functions to class methods wherever possible [Meye2000].

Hence, our classified implementation might look like the class UInteger64 (see Listing 4.1), which aggregates a uinteger64 as a member variable (so that it may reuse the UI64_*() API).

Listing 4.1.


class UInteger64


{


public:


  UInteger64();


  UInteger64(uint32_t low);


  UInteger64(uint32_t high, uint32_t low);


#ifdef ACMELIB_COMPILER_SUPPORTS_64BIT_INT


  UInteger64(uint64_t low);


#endif /* ACMELIB_COMPILER_SUPPORTS_64BIT_INT */


  UInteger64(UInteger64 const &rhs);


  . . .





// Comparison


public:


  static bool IsLessThan(UInteger64 const &i1, UInteger64 const &i2);


  static bool IsEqual(UInteger64 const &i1, UInteger64 const &i2);


  static bool IsGreaterThan(UInteger64 const &i1, UInteger64 const &i2);





// Arithmetic operations


public:


  static UInteger64 Multiply(UInteger64 const &i1, UInteger64 const &i2);


  static UInteger64 Divide(UInteger64 const &i1, UInteger64 const &i2);





private:


  uinteger64  m_value;


};




      Previous section   Next section