?
Solved

Calling a parent class function from a child class

Posted on 2005-04-08
9
Medium Priority
?
209 Views
Last Modified: 2013-11-20
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.
0
Comment
Question by:adamlevi
  • 2
  • 2
  • 2
  • +2
9 Comments
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 13737014
You need to cast.  

void *pParent  --- void doesn't have a member function AddToLog
0
 
LVL 86

Expert Comment

by:jkr
ID: 13737761
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
 

Author Comment

by:adamlevi
ID: 13738702
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 86

Expert Comment

by:jkr
ID: 13738781
>>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
 
LVL 9

Expert Comment

by:rcarlan
ID: 13742070
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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 13742858
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
 
LVL 9

Expert Comment

by:rcarlan
ID: 13743109
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
 
LVL 30

Accepted Solution

by:
Axter earned 500 total points
ID: 13746796
>>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
 
LVL 30

Expert Comment

by:Axter
ID: 13746814
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

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Suggested Courses

750 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question