Accessing a function from a nested class

khrispy
khrispy used Ask the Experts™
on
Here's an outline some code I inherited and that I'm trying to modify.

The code has a class "A" with a public method..lets call it "SomeMethod()";

  class A
  {
    public:
      void SomeMethod();
  }

There is a class "B" that is derived from class "A".  A nested class "C" (derived from class "D") is defined within class "A".

   class B: public A
   {
      class C: public D
      {
        public:
           FunctionXX();
      }
      .
      .
      .
   }

I want to modify FunctionXX() in class C so that it calls function  "SomeMethod()" in class A.  

   void B::C::FunctionXX()      
   {
     .
     .
     SomeMethod();
     .
     .
   }

Is there a way of doing this without a compilation error or is what I'm trying to do not possible?  When I try to compile in MS Visual C++ I get the following compilation error:

"error C2327: 'B::A::SomeMethod': member from enclosing class is not a type name, static, or enumerator"

The compiler is able to determine the location of the "SomeMethod" function but then complains about trying to access it.  

Note: I cannot make SomeMethod a static function as it is not operating on static variables.



Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
You could make declare a static function as a wrapper to your SomeMethod function. What you need it to get hold of this-pointer to be able to call SomeMethod for your object.

In your static wrapper function, you pass the pointer to the object as an argument. I believe I have written the code in here somewhere.... hmm maybe I can find it.
EOL

Commented:
This is a solution how I would deploy it.

#include <iostream>
using namespace std;

class A
{
public:
     void Foo(){ cout << "Foo from A" << endl; }
};

class B
{
public:
     void Foo(){ cout << "Foo from A" << endl; }
};

class C:public A
{
public:
     C():d(this){}
     void Bar(){ d.Bar(); }
     class D
     {
     public:
          D( C* c ):pc(c){}
               void Bar(){ pc->Foo(); }
          C* pc;
     };

     D d;
};

void main()
{
     C c;
     c.Bar();
}
EOL

Commented:
The compiler in your above example boggles you because you'r stretching the concept of classes as namespaces a bit too far.  The key difference between upscooping in a namespace and doing the same in a class is that in the process of doing it for a class the this pointer isn't delivered anymore.
Thus you can only compile things into your subclass that are known at compile time, to which the this pointer doesn't belong.
Bootstrap 4: Exploring New Features

Learn how to use and navigate the new features included in Bootstrap 4, the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first websites.

Commented:
well, I didn't find it but I could write some:


#include <iostream>

using namespace std;

class A
{
public:

     A(int id) : m_id(id) {}


     static void SomeMethodWrapper(A& obj)
     {
          obj.SomeMethod();
     }

     void SomeMethod()
     {
          cout << "object nr " << m_id << endl;

     }
     
     int m_id;
};


class D
{
};


class B: public A
{
public:
     
     B() : A(0) {}
     
     class C: public D
     {
     public:
          void FunctionXX(const A& obj)
          {
               obj.SomeMethodWrapper(const_cast<A&>(obj));    
          }
     };

     C m_C;
};




int main()
{

     A obj_1(1);
     A obj_2(2);

     B caller;

     caller.m_C.FunctionXX(obj_1);
     caller.m_C.FunctionXX(obj_2);

     return 0;
}



Commented:
What? You wanna call the very object A where FunctionXX resides?


#include <iostream>

using namespace std;

class A
{
public:

     A(int id) : m_id(id) {}


     static void SomeMethodWrapper(A& obj)
     {
          obj.SomeMethod();
     }

     void SomeMethod()
     {
          cout << "object nr " << m_id << endl;

     }
     
     int m_id;
};


class D
{
};


class B: public A
{
public:
     
     B(int id) : A(id), m_C(*this) {}
     
     class C: public D
     {
     public:
         
          C(const A& base) : m_base(base) {}

          void FunctionXX()
          {
               A::SomeMethodWrapper(const_cast<A&>(m_base));    
          }
     
           const A& m_base;
     };

     C m_C;

     
};


int main()
{

     B caller_1(1);
     B caller_2(2);

     caller_1.m_C.FunctionXX();
     caller_2.m_C.FunctionXX();

     return 0;
}


****************

That's it, I am not gonna code anymore tonight

Commented:
khrispy,
It would be better if we could see the actual code.

I just compile the following to VC++ 6.0, and it compiled with no problem:
class A
{
public:
     void SomeMethod(){}
};

class D: public A
{
public:
};


class B: public A
{
public:
     class C: public D
     {
     public:
          void FunctionXX();
     };
};

void B::C::FunctionXX()
{
     SomeMethod();
}

So I have a few questions.

1. Are you class D derives from class A?

2. What version of VC++ do you have (6.0 or 7.0)?

3. Are you missing any simicolons in your code, as you are in the code you posted?  In other words, do you have semicolons at the end of all your class declaration, including the inner class?

4. Are you missing the return type for your functions as you are for your posted example?

5. Can you post the actual code you're having problems with?

Commented:
Correction for question 1.

1. Are you SURE your class D is derived from class A?

Commented:
If D is not derived from class A, then you can't directly call SomeMethod() function because it's not part of class C or it's parrent class.

Commented:
hmm maybe I am thinking of something completly different.
EOL

Commented:
Axter your solution doesn't fit what khrisy wanted.

He tried to access a function of the base superclass, for which he needs a reference to the superclass.

Commented:
>>He tried to access a function of the base superclass,
>>for which he needs a reference to the superclass.

That's not how I interpret his question.
He states the following:

>>There is a class "B" that is derived from class "A".  A
>>nested class "C" (derived from class "D") is defined
>>within class "A".
The last part of his sentence seems to indicate that class D is derived from class A.

The he states:

>>I want to modify FunctionXX() in class C so that it
>>calls function  "SomeMethod()" in class A.  

So, if I'm correct, he's trying to access the parrent class function (A->D->C) and not (A->B).

But the only way to know for sure, is to get verification from the questioner.

Commented:
OK, in reading it again, he could be saying that he has the following:

class A
{
public:
     void SomeMethod(){}
     class D
     {
     public:
     };
};



class B: public A
{
public:
     class C: public A::D
     {
     public:
          void FunctionXX();
     };
};

void B::C::FunctionXX()
{
     SomeMethod();
}

Of course, the above code will not compile, because D does not have access to class A's SomeMethod().

Hopefully, he's talking about D being a decendent of class A, because that's easily do-able.
Commented:
Well, I did understand it this way.

He tried this:

class SuperBase
{
public:
     void SuperBaseFunc(){}
};

class SubBase
{
};

class SuperClass: public SuperBase
{
public:
     class SubClass: public SubBase
     {
          void Foo(){ SuperBaseFunc(); }
     };
};

Where he should handle it so:

class SuperBase
{
public:
     void SuperBaseFunc(){}
};

class SubBase
{
};

class SuperClass: public SuperBase
{
public:
     SuperClass():subC(this){}
     class SubClass: public SubBase
     {
     public:
          SubClass( SuperClass* sc ):superC(sc){}
          void Foo(){ superC->SuperBaseFunc(); }
          SuperClass* superC;
     };
     SubClass subC;
};
EOL

Commented:
The intresting thing is that such a situation can arise in a python programm and you can solve it by using namespace upscoping, whereas you have to pass a reference in c++.

Commented:
The problem is that in C++, a nested class does not know nothing about the enclosing class.  In other words, the statement:

    struct Enclosing {
        struct Nested {};
    };

Only says that the name Nested is defined inside the scope of Enclosing.  That is, you use it like this:

    Enclosing::Nested n;

In Java, for example, an inner class contains a pointer to an outer class which, I guess, is the behaviour you are trying to mimic.

Therefore, you need to manually supply a pointer (or reference) to the enclosing class when you construct the nested class.

I modified your example so it will now work correctly (I used structs for breivity):

    struct A {
        void SomeMethod() { cout << "OK" << endl; }
    };

    struct D {
        D(A& anA): myA(anA) {}
        A& myA; // a reference to an enclosing class
    };

    struct B: A {
        struct C: D {
            C(A& anA): D(anA) {}
            void FunctionXX();
        };
    };

    void B::C::FunctionXX() {
        myA.SomeMethod();
    };

    int main() {
        A a;
        B::C c(a);
        c.FunctionXX();
    }
EOL

Commented:
It's not that the code works anyhow better, but agreeably it is shorter and a bit nicer since it takes into account that polymorphism is herer for interfacing.
On the other hand I do use nested classes more often inside the superclass then outside, if I want to propagate them ot the outer world, why make them inside in the first place.

Commented:
Hey, I cut and pasted most code so I should get the credits! :)

Author

Commented:
Sorry folks,

My bad. There was a typo in my question.  The example code fragments are correct.  It is my comment about Class C being nested/defined inside class A that is incorrect.  I should have stated it is nested inside class B as was shown in the code sample.  

Unfortunately I'm unable to supply the actual code for proprietary reasons.  However my code sample does match what was done in the actual code I inherited.  My desired change to the original code (which works) was to try to add the SomeMethod() call within the C::FunctionX().
 
Also in response to some Axter's questions:
  -I am using Visual C++ 6.0.  
  - Class D is not derived from Class A (my typo probably
     confused you on this)
  - all necessary semi-colons are present in the actual
    code (another typo in my code sample...sorry)
 
I will read over and give all your other suggested solutions a try later this afternoon.  I've never used pointers to functions or static functions before so it might take me awhile to understand and try all your suggestions.

In the meantime my work-around to the problem was just to copy the code in the A::SomeMethod() function into the body of the C::FunctionX().  This was a lot of code duplication that I was hoping to avoid.

Author

Commented:
Hi,

Due to other pressing issues at work, I unfortunately was unable to spend time in testing out the suggestions this afternoon as I originally intended.  I'm on vacation all of next week and will re-test when I get back.

Commented:
hey, don't get busy being too fair. I don't mind about justice. Give the points to me.

Commented:
I guess I was right on the target from the very beginning! :)
EOL

Commented:
Kimpan, you'r a cheap point fag you know ;)

Author

Commented:
Hi,

Although both Kimpan's and Alexo's inputs were very helpfiul and probably correct, I gave EOL the 150 points since it was his example I used in my code which worked.  Seems like all I needed to do was to pass a pointer for the enclosing class to the nested class to make everything work in my case.  I didn't need to create a wrapper function as suggested in Kimpan's inputs.

Since Kimpan's and Alexo's inputs were still helpful and basically similar in concept to EOL's answer, in the spirit of the upcoming holidays, I will ask community support to also give Kimpan and Alexo 75 points each.

Commented:
No, my input was not similar in concept at all to EOL's answer. Don't compare me to that guy!
EOL

Commented:
hehe, we'r all weirdos, we know? :)

Commented:
I beg to differ.
EOL

Commented:
you heard it guys.

"basically similar to EOL." We'v something in common, it's hard I know.

But wish granted, alexo you differ.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial