Access to children in parent class, C ++

I came across a situation where I need to access descendant member variables inside the parent class. I know that this contradicts the principles of OO, but I have to deal with a scenario in which hundreds of classes are inherited from one, and half of them stop using one of the parent variables along the way and declare and use their own (it was necessary to switch from int to int [], and obviously the one who did this did not take into account the application of these changes in the parent class).

One option is to have a virtual function to handle this, but that means I have to change the code in hundreds of files / objects and check each one. So I thought that if you could use some old-school C pointer magic to access these variables inside the parent method, this would eliminate the need for 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 possible. If so, how do I achieve this.
Other suggestions are welcome, but keep in mind that I would only like to make changes to the parent class.
TIA.

+6
source share
9 answers

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 is also a yucky way to do this:

 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 does not have virtual functions, then dynamic_cast will not work. Although any class intended for inheritance must have at least one virtual function, even if it is only a destructor.)

+6
source

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 compiles - maybe not what you require - but then provide the best (= compiled) code example.

+4
source

If you are allowed to modify the source code of your child classes, you can do something like this:

 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 a virtual table (at least one virtual method), you can use static_cast () in combination with the C ++ 11 typeid, because it is 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; } }; 
+2
source

I do not get downvotes for static cast. The following works:

 #include <stdio.h> class B; class A { public: A(); void print(); private: B *child; }; class B : public A { friend class A; public: B(); private: int value; }; A::A(){ child = static_cast<B*>(this); } void A::print(){ printf("value = %d\n", child->value); } B::B(){ value = 10; } int main(){ B b; bA::print(); } 

Just make sure to place function declarations of A after class B. You can distinguish between child classes because a static cast will return non-NULL if you find the right child. I believe that this approach is also beneficial because the Child (B) class is practically unchanged.

+1
source

Apparently you have a subset of the derived classes that use childMember . For these classes, you have a DoSomething () method that you can call. I believe that for all other derived classes, the DoSomething() method is not applicable. Why don't you create another level of abstraction for this set of derived classes?

 class Parent { // no DoSomething() } class ChildMemberClasses : Parent { int childMember; void DoSomething() { // code that uses childMember } } class ChildWithChildMember : ChildMemberClasses { // other stuff } 

If DoSomething() has some meaning for classes without childMember, you can still define it as a virtual method in Parent . Like this:

 class Parent { virtual void DoSomething() { // code that does not use childMember } } class ChildMemberClasses : Parent { int childMember; void DoSomething() { // code that uses childMember } } class ChildWithChildMember : ChildMemberClasses { // other stuff } 
0
source

You can use a curiously repeating pattern template 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>; }; 
0
source

Will there be an intermediate intermediate class that contains the child member you need?

If yes:

 class Parent { virtual void DoSomething() //Parent must be a polymorphing type to allow dyn_casting { if (AbstractChild* child = dynamic_cast<AbstractChild*>(this)) { child->childMember = 0; } else //Its not an AbstractChild } } class AbstractChild : Parent { int childMember; virtual void DoSomething() = 0; } class Child1 : AbstractChild { virtual void DoSomething() { } } 
0
source

There is no reliable and reliable way to do this with pointers. You can crack smart pointer offsets, but this will rely on childMember showing up in the same place in all child classes.

-1
source

static_cast<Child*>(this)->childMember = 0; must work.

-2
source

Source: https://habr.com/ru/post/895870/


All Articles