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.
adamleviAsked:
Who is Participating?
 
AxterConnect With a Mentor Commented:
>>a requirement - that all such 'parent' classes need to expose a method with this signature: AddToLog(char*)

Actually, you can do this without the specific member function name requirement.
The only requirement you really need is a member function that can take the paticular type being pass to it.

Example code:
class CChild
{
public:    
      template<class P, typename F>
     void SetParent(P& pParent, F& func){
              (pParent.*func)('1');
     }
};

class CParent
{
public:
      CParent():child(new CChild)
       {
       }
     CChild * child;

     void Init()
     {
             typedef void (CParent::*MyMemberFuncType)(char msg);
             MyMemberFuncType ft = AddToLog;
             child->SetParent(*this, ft);
     }

     void AddToLog(char msg)
     {
             std::cout<<(msg);
     }
};
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
You need to cast.  

void *pParent  --- void doesn't have a member function AddToLog
0
 
jkrCommented:
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);
    }
};
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

 
adamleviAuthor Commented:
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.
0
 
jkrCommented:
>>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);
   }
};
0
 
rcarlanCommented:
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

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
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");
     }
};
0
 
rcarlanCommented:
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
0
 
AxterCommented:
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.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.