Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify constructor parameter values before calling base class constructor

Tags:

c++

I have following class hierarchy:

class Base { // This class cannot be modified
public:
  Base(int a, int b, int c) {
     if ( a == 100 && b == 200 && c < 100  ) // whatever condition
       throw "Error!";
  }
};

class Derived : public Base { // this class can be modified
public:
   Derived(int a, int b, int c) : Base(a, b, c) {}
};

class Derived is used in many places in code, so it cannot be replaced with some kind of factory function.

now the question is if there is some construct that would allow me to fix a,b,c values before calling Base constructor?

I know I can use functions like:

   Derived(int a, int b, int c) : Base(FixA(a), FixB(b), FixC(c)) {}

   int FixA(int a) { /*fix a value*/ return a; }
   int FixB(int b) { /*fix b value*/ return b; }
   int FixC(int c) { /*fix c value*/ return c; }

but it wont allow me to set correct values in case when a b c values are dependent like in above Base class c-tor example.

I was thinking of extending this to:

   Derived(int a, int b, int c) : Base(FixA(a,b,c), FixB(a,b,c), FixC(a,b,c)) {}

   int FixA(int a, int& b, int& c) { /*fix a b c values*/ return a; }
   int FixB(int& a, int b, int& c) { /*fix a b c values*/ return b; }
   int FixC(int& a, int& b, int c) { /*fix a b c values*/ return c; }

I suppose there should also be some kind of flag indicating that fix was already done. I am not sure if this is actually correct c++.

I know the best solution is to actually catch exception.

like image 556
marcinj Avatar asked Jan 16 '23 21:01

marcinj


2 Answers

Consider interposing a class between Derived and Base:

class Derived: public UnpackToBase {
public:
    Derived(int a, int b, int c): UnpackToBase(FixParameters(a, b, c))

class UnpackToBase: public Base {
public:
    UnpackToBase(FixParameters params): Base(params.a, params.b, params.c)

struct FixParameters {
    int a, b, c;
    FixParameters(int a, int b, int c): a(a), b(b), c(c) {
         // do stuff
    }

In C++11 you can use a delegating constructor of Derived:

class Derived: public Base {
public:
    Derived(int a, int b, int c): Derived(FixParameters(a, b, c)) { }
    Derived(FixParameters params): Base(params.a, params.b, params.c) { }
like image 164
ecatmur Avatar answered Feb 04 '23 15:02

ecatmur


You can use the singleton pattern to resolve this. Please see the code below. Here the order of initialization of the construction initialization list doesn't matter. However, I'm doubtful, if this can be called elegant.

class Base 
{ 
    // This class cannot be modified 
public:   Base(int a, int b, int c) 
          {      
              if ( a == 100 && b == 200 && c < 100  ) // whatever condition
                  throw "Error!";   
          } 
};  

class Validator
{
public:

    static Validator& instance(int a_in, int b_in, int c_in)
    {
        static Validator v(a_in,b_in,c_in);

        return v;
    }



    int& a(){ return m_a;}
    int& b(){ return m_b;}
    int& c(){ return m_c;}

private:

    Validator(int a_in, int b_in, int c_in) : m_a(a_in), m_b(b_in), m_c(c_in)
    {
        //  perform validation and modify the members
        //  Example validation
        if(m_a > 0 && m_b > 0)
        {
            m_c = 0;
        }
    }

    int m_a;
    int m_b;
    int m_c;
};

class Derived : public Base 
{ 
    // this class can be modified 
public:    
    Derived(int a, int b, int c) : Base(Validator::instance(a, b, c).a(), Validator::instance(a, b, c).b(), Validator::instance(a, b, c).c())
    {} 
};

int _tmain(int argc, _TCHAR* argv[])
{
    Derived d(1,2,3);

    return 0;
}
like image 36
PermanentGuest Avatar answered Feb 04 '23 17:02

PermanentGuest