It is currently Sat Aug 19, 2017 4:05 am

All times are UTC - 5 hours




 Page 1 of 1 [ 11 posts ] 
Author Message
 Post subject: Classes using preprocessor directives using inheritance?
PostPosted: Thu Sep 20, 2012 6:40 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
I am working on a trivial problem. I have a base class Coefficient, this class will not be used directly only its inherited classes will be used. I have a pair of setter and getter functions that I am defining and are both templated. I can not have the base class use a virtual function since the two derived classes have different datatypes associated with them. The two derived classes are Real and Complex. I didn't want to template the whole class, only the functions that need to be. I could of easily written the set and get functions for each class within themselves, however I was planning on the base class being responsible for this. I was trying to use preprocessor directives using define macros to chose which version of the function to use.

class Base {

protected:
#ifdef REAL_VALUE
   template <class T>
   inline void setCoefficient( T& RealCoefficient );
   
  template <class T>
   inline T  getCoefficient() const;
#else
   template <class T>
   inline void setCoefficient( std::complex<T>& ComplexCoefficient );
   
   template <class T>
   inline std::complex<T> getCoefficient() const;
#endif

};


this is the idea I have and inside the derived classes constructors is where I was planning on defining the macros, however it isn't working like I am expecting. Any comments or suggestions would help greatly.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Tue Oct 02, 2012 5:28 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
have you looked at template specialization? google it!


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Tue Oct 02, 2012 9:59 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
Yes, and a lot of it is cryptic, hard to follow or incomplete, in most cases the template examples I do see are good for doing basic templates, but doesn't quite fit my needs.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Thu Oct 04, 2012 10:46 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
well, this is what I can get to work with throwing some exceptions:

#ifndef MYCLASS_H
#define MYCLASS_H

class Base {
public:
   enum Type { REAL, COMPLEX };
   
protected:
   Type _t;
   explicit Base( Type t ) : _t( t ) {}
   
};

template < Base::Type t, class T >
class Coefficient : public Base {
private:
   T            _real;
   std::complex<T> _complex;
public:
   Coefficient( ) : Base( t ) { }
   
   void setReal( T& value ) {
      if ( _t == REAL ) {
         _real = value;
      } else {
         throw std::string( "Invalid Type: Base::COMPLEX - Expected a Complex Value This Function Has No Use" );
      }
   }

   T getReal() const {
      if ( _t == REAL ) {
         return _real;
      } else {
         throw std::string( "Invalid: Return value is not a real value" );
      }
   }

   void setComplex( std::complex<T>& value ) {
      if ( _t == COMPLEX ) {
         _complex = value;
      } else {
         throw std::string( "Invalid Type: Base:REAL - Expected Real Value This Function Has No Use" );
      }
   }

   void setComplex( T& realPart, T& imagPart ) {
      if ( _t == COMPLEX ) {
         _complex = std::complex<T>( realPart, imagPart );
      } else {
         throw std::string( "Invalid Type: Base:Real - Expected Real Value This Function Has No Use" );
      }
   }

   std::complex<T> getComplex() const {
      if ( _t == COMPLEX ) {
         return _complex;
      } else {
         throw std::string( "Invalid: Return value is not a complex value" );
      }
   }

};   

#endif // _MY_CLASS_H


If you set Type::REAL and pass in the datatype expected the setReal and getReal functions work fine, if you try to call the getComplex() it throws a std::string which main catches, if you try to call the getReal() function it works.

The same works for Type::COMPLEX, however the only difference is there are to setComplex() functions, one takes an std::complex<T> variable and the second takes 2 <T> values one for the real and one for the imag and creates an std::complex<T> variable from them. I made progress this far, but I am always looking to improve and simplify code even more. It would be nice to have a templated class that will take the data type passed such as int, double float ect... and depending on the constructor called would either create a T data member with its accessor functions or a
complex<T> data member with its accessor functions. I would like for it to be the way I am describing so that when the class is used, if a Real # is passed, the complex is hidden, if an std::complex<T> or T& real, T& imag is passed the Real # is hidden, now if a complex # is used, and a user wants to know the real compent they can access it from the std::complex<T> variable's *.real(). Eventually I will be incorperating this into a class that is called Term that consist of two containers an std::vector<char> and an std::vector<unsigned int> one is for each variable in the term and the other for the corresponding exponents. the two sizes of the containers must be == . Plus a few other variables that will contain its behavior or properties such as variable count, highest order of exponents is the term constant or not.
Yes a Term class can be constant if and only if the two associated containers are empty then it only has a Coefficient part which would either be REAL or COMPLEX. Then it is a matter of comparing, adding and subtracting of terms. This will then be encapsulated into a Polynomial Class. It is amazing how one of the easiest mathematical formulas to represent a complete set of expressions, is one of the hardest to generically program, lol.... But I like the challenge!!!


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Fri Oct 05, 2012 4:42 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
You should be able to simplify this since a real number is no different than a complex number that has an imaginary part that is zero.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Fri Oct 05, 2012 10:26 am 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
Yeah I thought about it, just using the std::complex<T> variable and omitting just the real part, but in most cases, a majority of polynomials have only a real, I didn't want the need for an std::complex<T> unless if it is needed and specified by the user, but then again, I could always have a setup like this.

T _realValue;
T _imagValue;
std::complex<T> _complex;

and in the setFunc() and or constructor of the class have func( T& _realValue, T& _imagValue = 0 ) { ... }
and once the members are saved and valid I could then pass them into _complex.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Fri Oct 05, 2012 3:14 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
I did a little revision of the code, I am know longer inheriting from a base class, i just moved the enum into the class and kept it a private enum to keep track if it is REAL or COMPLEX. I now have 4 constructors and a few overloaded accessor functions, a couple bool return functions, and a private helper function to make sure that both the individual T& _real, _imag variables are always aligned with _complex.real / x and _complex.imag / y variables. The class is also smart enough to know that if either _imag or _complex.imag / y is equal to 0, it will auto matically change its type to REAL

template < class T = double >
class Coefficient {
public:   
private:
   enum Type { UNKNOWN = -1, REAL, COMPLEX };
   Type         _type;
   T            _real;
   T            _imag;
   std::complex<T> _complex;
public:
   Coefficient() : _type( UNKNOWN ), _real(0), _imag(0), _complex( std::complex<T>(0,0) ){}

   explicit Coefficient( T& real ) :
      _type( REAL ), _real( real ), _imag( 0 ),
      _complex( std::complex( _real, _imag ) )  {
         keepRealAndImagPartsSame();
   }

   explicit Coefficient( T& real, T& imag ) :
      _type( COMPLEX ), _real( real ), _imag( imag ),
      _complex( std::complex<T>( _real, _imag ) ) {
         // This constructor defaults to a Complex Type However, if the user passes
         // in 0 for our imag we then have to change our default _type from Complex to Real
         if ( _imag == 0 ) {
            _type = REAL;
         }
         keepRealAndImagPartsSame();
   }

   explicit Coefficient( std::complex<T>& complex ) : _type( COMPLEX ),
      _real( complex.real() ), _imag( complex.imag() ), _complex( complex ) {
         // This constructor takes a std::complex<T> and sets _type to COMPLEX
         // by default, however if the _complex.imag() == 0, we then have to change
         // our _type to REAL
         if ( (_imag == 0) || (_complex.imag() == 0) ) {
            _type = REAL;
         }
         keepRealAndImagPartsSame();
   }

   T& getRealCoefficient() const { return _real; }
   T& getImagCoefficient() const { return _imag; }
   T& getRealPartOfComplexCoefficient() const { return _complex.real(); }
   T& getImagPartOfComplexCoefficient() const { return _complex.imag(); }
   std::complex<T>& getComplexCoefficient() { return _complex; }

   void setCoefficient( const T& real ) {
      // This function takes only a real value if this instance is used it is automatically a real
      _type = REAL;
      _real = real;
      _imag = 0;
      _complex = std::complex<T>( _real, _imag );

      keepRealAndImagPartsSame();
   }

   void setCoefficient( const T& real, const T& imag ) {
      _type = COMPLEX;
      _real = real;
      _imag = imag;
      _complex = std::complex<T>( _real, _imag );

      // This function defaults to a Complex Type However, if the user passes in 0
      // for our imag then have to change our default _type from Complex to Real
      if ( _imag == 0 ) {
         _type = REAL;
      }
   
      keepRealAndImagPartsSame();
   }

   void setCoefficient( std::complex<T>& complex ) {

      // This functions takes a reference to a std::complex<T> and sets _type
      // to COMPLEX by default, however if the _complex.imag() == 0, we then
      // have to change our _type to REAL
      _complex = complex;
      _real = _complex.real();
      _imag = _complex.imag();

      if ( (_imag == 0) || (_complex.imag() == 0) ) {
         _type = REAL;
      }
      keepRealAndImagPartsSame();
   }

   bool isReal() const {
      if ( _type == REAL ) {
         return true;
      }
      return false;
   }

   bool isComplex() const {
      if ( _type == COMPLEX ) {
         return true;
      }
      return false;
   }

private:
   inline void  keepRealAndImagPartsSame() {
      switch ( _type ) {
         case REAL: {
            // Test both to see if they are not 0 if either one is not
            // the set _imag to 0, we will then set our _complex according
            // to our members
            if ( _imag != 0 || _complex.imag() != 0 ) {
               _imag = 0;
            }

            // We Need To Make Sure Our _complex.real is == to our _real
            if ( _complex.real() != _real ) {
               _complex = std::complex<T>( _real, _imag );
            }

            break;
         }
         case COMPLEX: {
            // This is a COMPLEX value, make sure our members _real, _imag reflect our _complex member
            if ( _imag != _complex.imag() ) {
               _imag = _complex.imag();
            }
            if ( _real != _complex.real() ) {
               _real = _complex.real();
            }
            break;
         }
      }
   }
}; // Coefficient


If there are any spots in this code where I might be missing a critical check, please let me know. Thank You!
I hope you enjoy this class. I still have some work to do with creating operators for it such as comparison, =, and +/-
+=/-= etc. and maybe even the ostream<< operator.

I am wondering if I could a union to simplify this?


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Sat Oct 18, 2014 10:11 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
Working on a new project and in this case I have a base class Vector. It is responsible for keeping track of the type of vector derived from it as well as which unit vectors are available. I will show the pseudo code for this set up.

template <typename T>
class Vector {
public:

// Trying to use preprocess directives to define which set of variables are available to each derived class based on type.
#if (_type == VECTOR2)
   const T i = 1;
   const T j = 1;
#else
#if (_type == VECTOR3)
   const T i = 1;
   const T j = 1;
   const T k = 1;
#endif
#endif

protected :
    // Defines The Types Of Dimensions For All Vector Classes
    enum VECTOR_TYPE {
        VECTOR2 = 0,
        VECTOR3,
        //VECTOR4,
    }; // Add More For Higher Demensions (User Must Implement Higher Order Vectors Classes)
private:
    VECTOR_TYPE _type;
public:
    virtual ~Vector(){}
protected:
    inline explicit Vector( VECTOR_TYPE type ) : _type(type) {}
}; // Vector

template<typename T>
class Vector2 : public Vector<T> {
    ...
};

template<typename T>
class Vector3 : public Vector<T> {
    ...
};


In the description of the Base Class Vector The comment explains what I am trying to achieve. I know I could easily just use (const T variables) in each class independently) however since the base class does not have that much of a responsibility it would be nice to keep it there. Even using a for loop through the types to add an additional unit vector would be nice too. If I was to create a vector4,5,6,7 etc. classes afterwards this would make a nice feature. I may implement a vector4 but other than that I do not think there is a real need for any higher dimensions, but to automate the process would be great. So if a another user is to add another enumeration to the type then add the inherited template class this base class would automatically generate all the base unit vectors of that dimensional vector. I'm just not all that good with preprocessor directives and macros since a majority of this is more C style then C++. Any tips, suggestions or examples would be nice.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Sun Oct 19, 2014 6:57 am 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
I would structure it a little differently and get rid of _type like this:

class Vector {
public:
   virtual ~Vector();
protected:
   Vector();
};

template <typename T>
class Vector2 : public Vector
private:
   T i;
   T j;
};

template <typename T>
class Vector3 : public Vector
private:
   T i;
   T j;
   T k;
};



Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Sun Oct 19, 2014 1:38 pm 

Joined: Sat Aug 16, 2008 7:58 am
Posts: 448
That is what I originally had. Yes it is simple. And if that is the case, I could just remove the base class all together and just have each vector class templated. However If I was to have a container that holds all vectors regardless of their type, that is where the base class would come into play.


Offline
 Profile  
 
 Post subject: Re: Classes using preprocessor directives using inheritance?
PostPosted: Sun Oct 19, 2014 6:34 pm 
Site Admin

Joined: Sun Feb 11, 2007 8:59 am
Posts: 1105
Location: Ontario Canada
skilz80 wrote:
However If I was to have a container that holds all vectors regardless of their type, that is where the base class would come into play.


Exactly, that is why I recommend you keep the base Vector class, but then use templated inherited Vector2 and Vector3 classes so that you can put them into a common container.


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 11 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  

cron