I am facing a situation where I need to access child member variables inside the parent class. I know this is against OO principles but I have to deal with a scenario where hundreds of classes are inheriting from one and along the way half of them stopped using one of the parents variable, and declared and used their own (there was need to switch from int to int[] and apparently the person who did that didn't take in consideration to apply this changes in the parent class instead).
One option is to have a virtual function to deal with it, but this means I have to change the code in hundreds of file/objects and test each one of them. Hence I thought if it is possible to use some old school C pointer magic to gain access to this variables inside the parent method, this will eliminate the need of hundreds of virtual functions.
Basically this is what I want to achieve:
class Parent
{
void DoSomething()
{
// This is what I need
childMember = 0;
}
}
class Child1 : Parent
{
int childMember;
}
class Child2 : Parent
{
int childMember;
}
Please let me know if this is even possible. If yes how do I achieve that.
Other suggestions are welcomed, but keep in mind that I'd like to make changes only in the parent class.
TIA.
You can use the curiously recurring template pattern to achieve this.
template<typename T>
class Parent
{
void DoSomething()
{
// This is what I need
T::childMember = 0;
}
virtual ~Parent() {}
};
class Child1 : Parent<Child1>
{
int childMember;
friend class Parent<Child1>;
};
If you're allowed to change your child classes source code, you can do something like that:
class Parent
{
public:
void DoSomething()
{
getMember() = 0;
}
virtual int & getMember() = 0;
};
class Child1 : public Parent
{
int childMember;
public:
int & getMember()
{
return childMember;
}
};
class Child2 : public Parent
{
int childMember;
public:
int & getMember()
{
return childMember;
}
};
Otherwise, if your object has virtual table (at least one virtual method), you can use static_cast() in combination with C++11 typeid, because it's about three times faster than dynamic_cast:
#include <typeinfo>
class Parent
{
public:
virtual void DoSomething();
};
class Child1 : public Parent
{
public:
int childMember;
};
class Child2 : public Parent
{
public:
int childMember;
};
void Parent::DoSomething()
{
if (typeid(Child1) == typeid(*this))
{
auto child = static_cast<Child1*>(this);
child->childMember = 0;
}
else if (typeid(Child2) == typeid(*this))
{
auto child = static_cast<Child2*>(this);
child->childMember = 0;
}
};
Probably CRTP helps here:
struct Parent
{
virtual void DoSomething() = 0;
};
template <typename Derived>
struct ParentProxy : Parent
{
virtual void DoSomething()
{
Derived* p = dynamic_cast<Derived*>(this);
p->childMember = 27;
}
};
struct Child1 : ParentProxy<Child1>
{
int childMember;
};
struct Child2 : ParentProxy<Child2>
{
int childMember;
};
int main()
{
Child1 child1;
Child2 child2;
Parent* objects[] = { &child1, &child2 };
const int objectCount = sizeof(objects) / sizeof(objects[0]);
for (int index = 0; index < objectCount; ++index)
{
Parent* parent = objects[index];
parent->DoSomething();
}
}
I changed the code that it is compilable - probably not what you're requirements are - but then provide a better (=compilable) sample code.
The only clean way is to use the virtual function approach.
If the Parent
class has at least one virtual function (not necessarily DoSomething
), there's also a yucky way to do it:
void DoSomething() {
if (Child1* child = dynamic_cast<Child1*>(this)) {
child->childMember = 0;
} else if (Child2* child = dynamic_cast<Child2*>(this)) {
child->childMember = 0;
} // and so on, and so forth
}
(If Parent
has no virtual functions, then the dynamic_cast
won't work. Though, any class designed to be inherited from should have at least one virtual function, even if it's just the destructor.)
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