Link to home
Start Free TrialLog in
Avatar of adamlevi
adamlevi

asked on

Calling a parent class function from a child class

Hi folks!

I have the following code:
#include "stdafx.h"
#include "iostream.h"
#include "stdio.h"

class CChild
{
public:      
      void SetParent(void *pParent){
            pParent->AddToLog("1");
      }
};

class CParent
{
public:
      
      CChild * child;

      void Init()
      {
            child->SetParent(this);
      }

      void AddToLog(char msg)
      {
            cout<<(msg);
      }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
      CParent parent;
      parent.Init();

      return 0;
}

When I compile I get the following:
error C2227: left of '->AddToLog' must point to class/struct/union
The question is:
Why I can't point to the parent's AddToLog() function from child?
Do I have to cast the void pointer? Or the problem is the "this"?

Thanks.
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

You need to cast.  

void *pParent  --- void doesn't have a member function AddToLog
A lil' bit more precise - you code should be

class CParent; // forward declaration, so you can use 'CParent*'

class CChild
{
public:    
     void SetParent(CParent *pParent){
         pParent->AddToLog("1");
    }
};

class CParent
{
public:
   
     CChild * child;

    void Init()
    {
         child->SetParent(this);
    }

    void AddToLog(char msg)
    {
         cout<<(msg);
    }
};
Avatar of adamlevi
adamlevi

ASKER

I'll be more precise:

I don't want to include the CParent type in the CChild class. If I do that the CChild can't be generic, it'll work only with the CParent class.
>>I don't want to include the CParent type in the CChild class

No type, no way to call methods. That won't work. What you could do is using pure virtual interfaces, e.g.

interface ILogging {

virtual void void AddToLog(char* msg) = 0;
};

class CChild
{
public:    
     void SetParent(ILogging *pLog){
        pLog->AddToLog("1");
   }
};

class CParent : public ILogging
{
public:
   
    CChild * child;

   void Init()
   {
        child->SetParent(this);
   }

   virtual void AddToLog(char* msg)
   {
        cout<<(msg);
   }
};
There is also another solution: policy-based programming. It's similar in concept with interface-based programming (the solution presented by jkr above). The main difference is in the implementation. Policy-based programming completely decouples client from service and doesn't impose class hierarchy restrictions.

You can change your code to this:

class CChild
{
    public:
        template <class Parent>
        void SetParent<Parent& p) {p.AddToLong("1");}
};

You can now use CChild::SetParent with any number of classes, as long as they have a method AddToLong(const char*). This means the Parent classes do not have to derive from a common base interface.

This technique is used extensively in STL.

Radu

If you are only using it with some classes you could have a common base class for the parent

CParent : public CBaseParent
{
....
  virtual void AddToLog() = 0;   //pure virtual class
}


and
class CChild
{
public:    
     void SetParent(CBaseParent *pParent){
          pParent->AddToLog("1");
     }
};
I'm sorry to repeat myself, but I have to disagree with Andy. You do *not* have to have a common base class.

All you need is to establish a logical policy - a requirement - that all such 'parent' classes need to expose a method with this signature: AddToLog(char*)
The method doesn't have to be virtual and indeed these 'parent' classes do not have to be related in any way - i.e. they do *not* have to inherit from a common class.
Policy-based programming is similar in concept with interface-based programming, but the implementation of this concept is quite different. There's total decoupling and no class hierarchy restrictions. STL and ATL both make heavy use of policy-based programming.

To take Adam's code:

class CChild
{
    public:
        template <class Parent>
        void SetParent(Parent* p) {p->AddToLog("1");}
};

class CParent
{
public:
     
     CChild * child;

     void Init()
     {
          child->SetParent(this);
     }

     void AddToLog(char* msg)
     {
          cout<<(msg);
     }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
     CParent parent;
     parent.Init();

     return 0;
}


This will compile (though it will crash, because the child data member is not initialised:-).

Not only would this compile, but also this:

class CAnotherParent
{
     public:
          void AddToLog(char* msg)
          {
               printf(msg);
          }
};

Child c;
CAnotherParent ap;
c.SetParent(&ap);

Radu
ASKER CERTIFIED SOLUTION
Avatar of Axter
Axter
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
With above example code, the CChild class doesn't need to know anything about the CParent class, and the only requirement for the CParent class is that it has a member that can take a type char type.
The SetParent method is a template function that takes both the parent argument and the parrent member function argument.

FYI:
If you're using a  more compliant ++ compiler like VC++ 7.1, you don't even need the typedef code that is in the Init function.
The typedef code is needed for VC++ 6.0, which some times needs a little extra help to get template logic working.

Also:
#include "iostream.h"
#include "stdio.h"

When you use the above headers in your code, you should use the <> brackets.  Double quotes are usually used for custom headers, and <> brackets are used for implementation headers.

And <iostream.h> is not part of the C++ standard, and therefore not portable.  This non-portable header will not compile on VC++ 7.1
You should use <iostream> instead which is part of the C++ standard.