The Taligent Application Environment supports many color spaces: RGB, XYZ, Gray, and so on. In addition, developers can add new color spaces. Colors can be assigned to each other, even if they are different subclasses of TColor, the abstract base class of all colors. They can also be constructed from each other, effectively converting color spaces. Using colors like value-based objects makes them very developer friendly. For example:
TRGBColor rgb( .5, .5, .1); TRGBColor rgb2( rgb ); // Plain copy construction rgb2 = rgb; // Plain assignment TXYZColor xyz( rgb ); // Converting construction xyz = rgb; // Converting assignment
The trick is to define pure virtual casting operators in TColor which convert any given subclass to a TXYZColor. Any color subclass, therefore, has to know how to convert itself to the canonical XYZ color space.
Also, any color subclass should have a constructor that takes a single TXYZColor argument (unfortunately, this cannot be enforced with pure virtuals). Therefore, subclasses have to know how to do the conversion the other way around (from XYZ to their own type). Once these two things are in place, you can define a pure virtual assignment operator in TColor:
The optional type check improves efficiency by using a straight (nonconverting) assignment if the two objects are of the same TColor subclass. The else clause deals with polymorphic assignment: the argument is converted to a TXYZColor by the arguments override of the XYZ casting operator. That XYZ color is then passed to the XYZ color constructor of THLSColor. This way, the other color is first up-converted to XYZ (the canonical color space) and subsequently down-converted into the target color space. These conversions aren't necessarily cheap (they can involve matrix multiplies, and so on).
Color subclasses must also have a monomorphic assignment operator
Implementation
With real RTTI, TColor& THLSColor::operator=( const TColor& other )
{
if( typeid(other) == typeid(*this) ) // Fake RTTI calls
*this = (const THLSColor&)other; // Use our assignment
else
*this = THLSColor( other ); // Convert and use our assignment
}
typeid(*this)
can be replaced by typeid(THLSColor)
.
(see "When to use virtual assignment" on page 100).
two places.
// Temporary until RTTI support
#define typeid(x) *((x).GetMetaInformation()->GetClassNameAsToken())
// TColor base class
class TColor : {
...
virtual TColor& operator=( const TColor& other ) =0;
virtual operator TXYZColor() const = 0;
...
}
// an example color subclass
class THLSColor : public TColor {
...
THLSColor( const TXYZColor& other ); // converting ct
THLSColor( const THLSColor& ); // monomorphic copy constructor
virtual TColor& operator=( const TColor& other ); // polymorphic assignment
virtual operator TXYZColor() const; // conversion operator
...
THLSColor& operator=( const THLSColor& other ); // monomorphic assignment
...
}
[Contents]
[Previous]
[Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.