Home > Enterprise >  How do you access member functions of a class object from within a different class object that has b
How do you access member functions of a class object from within a different class object that has b

Time:10-31

class Class1  //Would be object mClass1
{
public:
 void Function1()
 {
  a  ;
 }
private:
 int a = 0;
 Class2 mClass2;
}

(Editing in a space here to clarify Class2 is not defined after Class1; they are in separate files.)

class Class2  //Would be object mClass2
{
public:
 Function2()
 {
  Function1();  // Would be from mClass1
 }
}

So Class1 creates an instance of a Class2 object, and that Class2 object has a member function that wants to access the "parent" object's member function, without using inheritance.

I don't know what I specifically need to search for to learn about this. Does it have to do with dereferencing a new pointer? Constructor type/initialization? Does it have a terminology? "Nested classes" bring up classes defined inside another class, which is not what this is.

CodePudding user response:

Without inheritance there is no way to get the 'parent class'. So instead you should just pass the function as a parameter, maybe in the constructor of class 2 if you use it multiple times. See for example: https://www.cprogramming.com/tutorial/function-pointers.html

CodePudding user response:

You cannot do this. Class2 is not known yet when you define Class1, so the Class1::mClass2 data member cannot possibly be created. But this problem can be solved by defining Class2 before Class1, and implementing Class2::Function2() outside the class and only after Class1.

As for calling Function1() inside Function2(), Class2 needs to know the object on which to call Function1(). You could use a reference member for that that you initialize in the constructor:

// Forward-declaration of Class1 so that Class2 will be able to define
// references or pointers to Class1.
class Class1;

class Class2
{
public:
    // Constructor that requires a reference to our parent object.
    explicit Class2(Class1& parent)
        : parent_(parent)
    { }
    
    // Just declare the function. We need to implement it later, outside
    // this class definition because Class1 is not fully known yet and as
    // a result we can't have calls to Function1() because the compiler
    // doesn't know that function yet.
    void Function2();
    
private:
    // This is just a reference, so it works even if Class1 is not fully
    // known yet.
    Class1& parent_;
};

class Class1
{
public:
    void Function1() { /* ... */ }

private:
    int a = 0;
    Class2 mClass2{*this}; // Pass ourself as the parent object.
};

// Class1 is fully known now, so we can do calls to Function1().
inline void Class2::Function2()
{
    parent_.Function1();
}

This will work, but it has an important implication: it disables the assignment operator of Class2. This is probably what you want in this case, because two copies of Class2 should probably not have the same Class1 parent object.

However, I don't see why you need to do this. It complicates matters for no good reason. Why not simply pass the Class1 object that Function2() should use as a function argument instead? So:

class Class1;

class Class2
{
public:
    void Function2(Class1& c1_obj);
};

class Class1
{
public:
    void Function1() { /* ... */ }

private:
    int a = 0;
    Class2 mClass2;
};

inline void Class2::Function2(Class1& c1_obj)
{
    c1_obj.Function1();
}

So whenever Class1 needs to call Class2::Function2(), just pass *this to it. It's simpler and doesn't have the drawbacks of holding a reference or pointer to another object.

CodePudding user response:

With canonic classes - no way to do this, because Class2 is incomplete within Class1 and if you declare Class2 inside of Class1 (as a nested class), it wouldn't have access to Class1, because Class1 incomplete!

Looks like an unsolvable paradox? It is unsolvable in OOP land, but can be dodged just like Nikos had shown. But the problem of undefined types in some cases can be resolved in C or similar concept-oriented languages by using CRTP - Curiously recurring template.

If it is possible or not in your use-case and how complex it would be depending on what purpose you pursue. Here is an example of a paradoxical CRTP behavior - a member of base class is able to call a member of derived class:

#include <iostream>

template < class T>
class Base { 

public:
      template <class U>
      struct Accessor : public U {
           static void evoke_foo( T& obj)
           {
                 return  (obj.*(static_cast< void(T::*)() >(&Accessor::foo))) ();
           }
      };

      void evoke(  )
      {  
           Accessor<T>::evoke_foo( *static_cast<T*>(this) );
      }
};


class Derived : public Base<Derived> {
protected:
      void foo()  { std::cout << "Foo is called" << std::endl; }
};


int main()
{
    Derived a;
    a.evoke();   // evoke belongs to base.
}

Now if we'd want to determine return type of foo() automatically here, this would become an insanely complex piece of code. Some problems like that are solved in implementations of standard namesake of evoke method.

  • Related