#pragma once ///////////////////////////////////////////////////////////////////// // Properties.h - defines template-based properties for C++ // // ver 2.0 // // Jim Fawcett, CSE687 - Object Oriented Design, Fall 2018 // ///////////////////////////////////////////////////////////////////// /* * Package Operations: * ------------------- * This package provides classes: * * - Property * -------------------- * Provides properties for all non-primitive types, e.g., classes. * GS is a class that provides get and set methods. * * - CDef * -------------------- * Defines default getter and setter methods, used for GS in class properties. * * - PDef * -------------------- * Defines default getter and setter methods, used for GS in primitive properties. * * - Property * -------------------- * A primitive property specialization for ints * * - Property * -------------------- * Specialization for size_t types, e.g., unsigned ints * * - Property * -------------------- * Specialization for doubles * * - Box * -------------------- * A wrapper class that boxes a primitive type so it can be used * like a class, e.g., be the base for inheritance. * * Required Packages: * ------------------ * Properties.h, Properties.cpp - only Properties.h is needed for applications * * Maintenance History: * -------------------- * ver 1.1 : 08 Sep 2018 * - large redesign, but using most of the original ideas. * Ver 1.0 : ?? * - first release */ #include #include ///////////////////////////////////////////////////////////////////// // CDef class // - defines default getter and setter functions for Property // - derives from T and so has an internal T element template class CDef : public T // deriving from T means that there is { // a T instance inside Def public: void set(const T& t) { // sets value of base T element T::operator=(t); } T get() { // gets copy of base T element so caller return *this; // can't change value without using set(t) } }; ///////////////////////////////////////////////////////////////////// // CRev class converts string to all caps // - compilation will fail for non string classes // - defines revised getter and setter functions for Property // - derives from T and so has an internal T element template class CRev : public T // deriving from T means that there is { // a T instance inside Def public: void set(const T& t) { // sets value of base T element T u = t; std::transform(u.begin(), u.end(), u.begin(), ::toupper); T::operator=(u); } T get() { // gets copy of base T element so caller // can't change value without using set(t) return *this; } }; ///////////////////////////////////////////////////////////////////// // Property class // - T is the property type // - GS is a template template parameter that defines the // property getter and setter methods. // - Using GS = CDef simply stores and retrieves the property value // - We define a new GS class with template parameter T if we need // to impose constraints on the setting and getting. Thats what // we did in CRev. // - GS methods get and set will contain logic to enforce whatever // conditions an application needs. template class GS> class Property : public GS // GS derives from its template parameter T { // and property inherits that T storage public: Property() {} Property(const T& t) { // copy construct Property from T instance set(t); } T operator=(const T& t) // assign t to the T element of property { set(t); return get(); } operator T() // unfortunately never called - compiler implements conversion { // from derived to base. This means that application can define // Widget& w = widgetProperty and change it without using set. // If application calls get(), no problem because get() returns // the property store by value. std::cout << "\n cast operation"; return get(); } void set(const T& t) { // use setter from GS GS::set(t); } T get() { // use getter from GS return GS::get(); } }; ///////////////////////////////////////////////////////////////////// // operator<< // - global operator defined for Property template class GS = CDef> std::ostream& operator<<(std::ostream& out, Property& p) { out << p.get(); return out; } ///////////////////////////////////////////////////////////////////// // PDef class // - provides getter and setter functions for primitives template class PDef { public: P get() { return p_; } void set(P p) { p_ = p; } private: P p_; }; ///////////////////////////////////////////////////////////////////// // Property // - property specialized for ints template class GS> class Property { public: Property() {} Property(int t) { set(t); } Property& operator=(int t) { set(t); return *this; } operator int() { return get(); } int get() { return gs.get(); } void set(int t) { gs.set(t); } private: GS gs; }; ///////////////////////////////////////////////////////////////////// // Property // - property specialized for size_t's template class GS> class Property { public: Property() {} Property(size_t t) { set(t); } Property& operator=(size_t t) { set(t); return *this; } operator size_t() { return get(); } int get() { return gs.get(); } void set(size_t t) { gs.set(t); } private: GS gs; }; ///////////////////////////////////////////////////////////////////// // Property // - property specialized for doubles template class GS> class Property { public: Property() {} Property(double t) { set(t); } operator double() { return get(); } Property& operator=(const double t) { set(t); return *this; } double get() { return gs.get(); } void set(double t) { gs.set(t); } private: GS gs; }; ///////////////////////////////////////////////////////////////////// // Box class // - wrapper for primitives that lets them use the property for classes // - wraps a primitive type in a class wrapper so it can be a base // for inheritance // - similar to C# boxing template class Box { public: Box() { } Box(const Box& b) { t_ = b.t_; } Box(const T& t) { set(t); } Box operator=(const T& t) { set(t); return *this; } operator T() { return get(); } void set(const T& t) { t_ = t; } T get() { return t_; } private: T t_; };