//+------------------------------------------------------------------+
//| 11:19 AM 2/6/2015 polymorphic.mqh |
//| Copyright © 2015, William H Roeder |
//| mailto:WHRoeder@yahoo.com |
//+------------------------------------------------------------------+
/** @file
* @brief Dynamic cast (RTTI) capability in MT4. */
//+------------------------------------------------------------------+
#ifndef POLYMORPHIC_MQH
#define POLYMORPHIC_MQH
#include "utility.mqh" // DISALLOW_COPY_AND_ASSIGN
/** Dynamic cast capability in MT4. Mt4 is like C++ except:
* - No const upcast. Build 765 won't compile `(const D*)p`.
* - No dynamic cast or RTTI
* - No exceptions - an invalid upcast __terminates__ the EA.
* - No multiple inheritance
* - No templated classes.
*
* Since there is no class templates, a `dynamic_cast` is impossible.
* Instead a template function `bool dynamic_cast(D*& dp)` is provided that
* converts a pointer to the object to the requested pointer type if possible.
*
* To provide the RTTI, a virtual function must be provided in all subclasses
* (where dynamic cast is required,) to follow the class hierarchy. The provided
* macro @ref POLYMORPHIC(`BASE`) does this. The macro should be placed in the
* `__protected__` portion. I recommend directly after the opening brace, or on
* the next line showing the two parent class names match.
*
* Example of use:
* ~~~~{.cpp}
* class B : public Polymorphic{ protected: POLYMORPHIC(Polymorphic);
* ... }; // B
* class D : public B{ protected: POLYMORPHIC(B);
* ... }; // D
* class E : public B{
* protected: POLYMORPHIC(B); //<< Base over Base shows names match.
* public:
* ... }; // E
* class F : public E{
* #define F_SUPER E
* protected: POLYMORPHIC(F_SUPER);
* public:
* void F(int i) : F_SUPER(i){}
* ... }; // E
* :
* B* bp = new D();
* D* dp; if(bp.dynamic_cast(dp)){ // bp is a D, dp is set and returns true.
* E* ep; if(bp.dynamic_cast(ep)){ // bp is not a E, ep=NULL, returns false.
* ~~~~
* Note in the above example I included a semicolon at the end of the macro
* call. It is optional (but doxygen gets confused without it,) since MT4 allows
* but doesn't require inline method definitions to have a semicolon:
* ~~~~{.cpp}
* class c{
* void method1(void){ something } // No semi.
* void methodm2(void){ something }; // A semi.
* }; // Semicolon at `class` definition is required.
* ~~~~ */
class Polymorphic{
protected: // Allow derived class to be copyable. // Abstract
void Polymorphic(){} // Ctor
void Polymorphic(const Polymorphic &){} // Copy
Polymorphic* operator=(const Polymorphic &){ // Assgn
return GetPointer(this);
}
public:
/** Upcasts the object to the _pointer_ of the given type.
* @param [out] dp A pointer to upcast to.
* @returns true if successful.
* @note The given pointer can not be __constant__ as Build 765 won't compile
* `(const D*)p`. This method is not `const` to disallow a nonconstant upcast
* using a `const this`. */
template
bool dynamic_cast(D*& dp) const{
string tn = typename(dp); bool isIt = this.affirm(tn);
dp = (D*)(isIt? GetPointer(this) : NULL); return isIt;
}
// No constant method, since Build 765 has no (const D*)
/** Cast the object to the _pointer_ of the given type. If the object is
* __not__ compatable, the EA will be __terminated__. */
template
void static_cast(D*& dp) const{dp = (D*)GetPointer(this); }
protected:
/// Affirm the the object is of the given _type_
virtual bool affirm(const string& type) const{return typename(this)==type;}
};
//+- Polymorphic ---------------------------------------------------+
/** Macro to follow the class hierarchy.
* ~~~~{.cpp}
* #define POLYMORPHIC(BASE) \
* virtual bool affirm(const string& tn) const OVERRIDE{ \
* return typename(this) == tn || BASE::affirm(tn); \
* }
* ~~~~ */
#define POLYMORPHIC(B) virtual bool affirm(const string& s)const{ return typename(this)==s||B::affirm(s);}
/** Provides a noncopyable polymorphic class. Mt4 doesn't have multiple
* inheritance so can't do this
* `class B : public Polymorphic, Noncopyable { ...` */
class Polymorphic_NC : public Polymorphic{ // Noncopyable
private: DISALLOW_COPY_AND_ASSIGN(Polymorphic_NC);
};
//+- Polymorphic_NC ------------------------------------------------+
#endif // POLYMORPHIC_MQH
//+------------------------------------------------------------------+