![]() | |
![]() ![]() |
![]() | Imperfect C++ Practical Solutions for Real-Life Programming By Matthew Wilson |
Table of Contents | |
Chapter 4. Data Encapsulation and Value Types |
4.6. Value TypesFrom the encapsulated types, it is a small step up to what I would call actual value types. In my opinion, the distinguishing characteristic of a value type is that it is EqualityComparable [Aust1999, Muss2001]: it provides meaningful responses, bearing in mind the Langer-Kreft [Lang2002] definition (see section 4.2), to equality and inequality tests. Since the compiler does not provide these operators for class types by default, we need to provide them. Fundamentally, we need types that do sensible things. The problem with encapsulated types is that they cannot be used in code that makes use of equality comparison. An important use for value types is to be placed in by-value containers, which includes those containers provided by the standard library. Although we can declare and manipulate instances of std::vector<UInteger64>, because it places no restrictions on the uniqueness of the elements it stores, we cannot search for a given type using the standard std::find<>() algorithm: std::vector<UInteger64> vi; vi.push_back(i1); vi.push_back(i2); vi.push_back(i3); std::find( vi.begin(), vi.end() , UInteger64(1, 2)); // Error! No op == for UInteger64 (Remember that std::vector<> maintains unordered sequences, so there's also no ordering comparison, and so no < operator, needed either.) Converting the type to be a full value type is very simple. Since the previous definition of UInteger64 provided an IsEqual() method, we can implement the (in)equality operators in terms of that, as in: inline bool operator ==(UInteger64 const &i1, UInteger64 const &i2) { return UInteger64::IsEqual(i1, i2); } inline bool operator !=(UInteger64 const &i1, UInteger64 const &i2) { return !operator ==(i1, i2); } The advantage here is that we've "promoted" the type to be a full value type by the addition of nonmember functions [Meye2000]. Since these functions were previously unavailable, there can be no extant code that depends on their presence (or absence), so we've achieved the enhancement with no maintenance connotations whatsoever. (Author's carp: it is the thoughtless eagerness to push everything into classes that lies behind a great many fat frameworks and C++'s undeserved reputation for inefficiency.) So, we can now look again at our value-type definition, and propose the following:[5]
|
![]() | |
![]() ![]() |