/*! * @file self.h * @brief Contains a class for implementing a reference mechanism which allows * variables referencing to another object anytime. * * @author cathook */ #ifndef __MEOWPP_UTILITY_SELF_H__ #define __MEOWPP_UTILITY_SELF_H__ #include namespace meow { /*! * @brief An implementation for the reference mechanism. * * Some example code: * @code{.cpp} * #include * * class A { * private: * * // Data members of this class. You can also move the methods of class A * // into this structure if you like. * struct DataMember { * int var1; * int var2; * int counter; * * // The constructor "Self::Self()" will call the constructor * // "DataMember::DataMember()" * DataMember() : var1(0), var2(0), counter(0) {} * * // The constructor "Self::Self(DataMember const&)" will call * // the constructor "DataMember::DataMember(DataMember const&)" * DataMember(DataMember const& b) : * var1(b.var1), var2(b.var2), counter(0) {} * * // Customize constructor. * DataMember(int var1_init_value) : * var1(var1_init_value), var2(0), counter(0) {} * * // Destructor, will be called when nobody references to it. * ~DataMember() {} * * // The "Self::CopyFrom(Self const&)" will call * // "DataMember::CopyFrom(DataMember const&)" to copy data. * DataMember const& CopyFrom(DataMember const& b) { * var1 = b.var1; * var2 = b.var2; * } * }; * * meow::Self const self_; // Use constant type to reduce the * // protential error caused by typing * // wrong. * * public: * * // Here the "Self::Self()" will be called. * A() {} * * // Notice! "Self::Self(Self const& another_self)" will let * // itself reference to the gived object instead of creating a new one. * // So here the copy constructor will not copy from the gived object, it * // will just reference from it. * A(A const& another_class_a) : self_(another_class_a.self_) {} * * // Customize constructor. * A(int var1_init_value) : self_(DataMember(var1_init_value)) {} * * // You don't need to call some extra function in destructor, because * // there's a counter in the Self class. * ~A() {} * * // A constant method. * int GetVar1() const { * return self_->var1; // Use the operator "->" to access the address of * // the DataMember. Because we declare self_ be a * // constant type, here "self_->var1" will also be * // a constant. * } * * // A non-constant method. * void SetVar1(int new_value) { * int old_value = self_->var1; * self_()->var1 = new_value; // Use operator "()" (i.e. self_()) to * // access the object with non-constant type, * // so here "self_()->var1" will be a * // non-constant variable. * if (old_value != new_value) { * self_()->var2 = old_value; * //self_->var2 = old_value; // !! It cause an error because operator "()" * // is missed if you want to modify the member * // in the DataMember. * } * } * * int GetVar2() const { * self_()->counter += 1; // !! It will not cause an error. Actually, * // the "const" keyword of a method will become * // more meanless, because inside the method, you * // can just use self_-> or self_()-> to determind * // whether you want to access the DataMember in * // constant mode or not. It might be dangerous * // but giving developer more flexable. * return self_->var2; * } * }; * @endcode */ template class Self { private: struct Body { int counter; SelfType body; Body() : counter(1) {} Body(SelfType const& arg_another_body) : counter(1), body(arg_another_body) {} }; Body* body_; /*! * @brief Attaches to another body. * @param arg_another_body Pointer to another body. */ void Attach(Body* arg_another_body) { body_ = arg_another_body; body_->counter += 1; } /*! * @brief Detaches from the current body. */ void Detach() { body_->counter -= 1; if (body_->counter == 0) { delete body_; } } public: /*! * @brief Creates a new one. */ Self() : body_(new Body()) {} /*! * @brief Creates a new one with specifying a initial value for SelfType * object. * @param arg_body The initial value of the SelfType object. */ Self(SelfType const& arg_body) : body_(new Body(arg_body)) {} /*! * @brief References from another one. * * @param arg_another_self Another Self object. */ Self(Self const& arg_another_self) { Attach(arg_another_self.body_); } /*! * @brief Detatches. * * It will automatically clear the SelfType object when no one refernece from * it. */ ~Self() { Detach(); } /*! * @brief References from another Self object. * @param arg_another_self Another Self object. */ Self const& ReferenceFrom(Self const& arg_another_self) { Detach(); Attach(arg_another_self.body_); return *this; } /*! * @brief Copies the data in SelfType object from another Self object. * @param arg_another_self Another Self object. */ Self const& CopyFrom(Self const& arg_another_self) { body_->body.CopyFrom(arg_another_self.body_->body); return *this; } /*! * @brief Creates a copy one of itself. */ Self Copy() const { return Self(body_->body); } /*! * @brief Checks whether the gived instance of Self references * from the same SelfType with me or not. * @param arg_another_self Another instance of Self. * @return true if we references from the same thing. */ bool Is(Self const& arg_another_self) const { return (body_ == arg_another_self.body_); } /*! * @brief Access the instance of SelfType by address */ SelfType* operator->() { return &(body_->body); } /*! * @brief Access the instance of SelfType by constant address */ SelfType const* operator->() const { return &(body_->body); } /*! * @brief Access itself in non-constant mode. */ Self& operator()() const { return *const_cast(this); } /*! * @brief Disallows the "operator=" so develops need to explicitly use * CopyFrom/RefernceFrom. */ Self& operator=(Self const& b); #ifdef MEOWPP_UTILITY_SELF_TESTING friend class SelfTest; #endif // MEOWPP_UTILITY_SELF_TESTING }; } // meow #endif // __MEOWPP_UTILITY_SELF_H__