Imperfect C++ Practical Solutions for Real-Life Programming By Matthew Wilson | |
Table of Contents | |
Chapter 29. Arithmetic Types |
29.1. Class DefinitionBefore we get stuck into the minutiae, we'll just take a look at the class definition. I decided, in order to avoid confusion with the two extant member variables lowerVal and upperVal, to use protected inheritance and derive a new type UInteger64. This is so we can cheat and use a union of uinteger64 and a uint64_t in order to perform the arithmetic. This relies on the correct layout of the two members in the structure, as follows:[1]
Listing 29.1.struct uinteger64 { #if defined(ACMELIB_LITTLE_ENDIAN) uint32_t lowerVal; uint32_t upperVal; #elif defined(ACMELIB_BIG_ENDIAN) uint32_t upperVal; uint32_t lowerVal; #else # error Need to discriminate further . . . #endif /* endian */ }; This allows us to do the following monstrosity, which, as I said, is merely for expediency for this specific type, rather than a technique one would use for large integers in general: Listing 29.2.class UInteger64 : protected uinteger64 { public: typedef union { uint64_t i; uinteger64 s; } ui64_union; ui64_union &get_union_() { uinteger64 *p1 = this; ui64_union *p2 = reinterpret_cast<ui64_union*>(p1); return *p2; } ui64_union const &get_union_() const; . . . It's not the way you'd start out and design a large integer class from scratch, where you'd not have the option of using a higher fundamental type in anything larger than 64 bits. The test harness for this chapter consists of a template function within which a variety of numeric operations are performed. We'll go through them all, and see the ramifications for the design of our class. |