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.
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) { }
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With