views:

61

answers:

3

Please see the example code below:

class A
{
private:
    class B
    {
    public:
        foobar();
    };
public:
    foo();
    bar();
};

Within class A & B implementation:

A::foo()
{
    //do something
}

A::bar()
{
    //some code
    foo();
    //more code
}

A::B::foobar()
{
    //some code
    foo(); //<<compiler doesn't like this
}

The compiler flags the call to foo() within the method foobar(). Earlier, I had foo() as private member function of class A but changed to public assuming that B's function can't see it. Of course, it didn't help. I am trying to re-use the functionality provided by A's method. Why doesn't the compiler allow this function call? As I see it, they are part of same enclosing class (A). I thought the accessibility issue for nested class meebers for enclosing class in C++ standards was resolved.

How can I achieve what I am trying to do without re-writing the same method (foo()) for B, which keeping B nested within A?

I am using VC++ compiler ver-9 (Visual Studio 2008). Thank you for your help.

A: 

If you want to reuse functionality from A then you should inherit from A not nest B inside it.

Gary
I am not extending the fucntionality of A in B, so, there's no need for inheriting B from A. Also, I would like to keep B hidden from the users of class A.
Rahul
+6  A: 

foo() is a non-static member function of A and you are trying to call it without an instance.
The nested class B is a seperate class that only has some access privileges and doesn't have any special knowledge about existing instances of A.

If B needs access to an A you have to give it a reference to it, e.g.:

class A {
    class B {
        A& parent_;
    public:
        B(A& parent) : parent_(parent) {}
        void foobar() { parent_.foo(); }
    };
    B b_;
public:
    A() : b_(*this) {}
};
Georg Fritzsche
+1, just a nitpick - `parent` is probably not the best name for member variable here - easy confusion with inheritance.
Nikolai N Fetissov
I just wanted to mention that there had be a very good design reason for the nested class B to have a reference to class A.
manifest
Thank you for the explanation with example. The C++ standard 11.8, which I was guessing that it had changed, talks about the class member access by nested class. I know that gcc allows the access by nested class (I'm sure about it) but MS VC compiler doesn't. Hmm... interesting.
Rahul
@Rahul: Yes, you have access privileges, but there is no implicit relationship between instances - its only a class of which you still have to create instances explicitly.
Georg Fritzsche
@Nikolai: Hm, i find it clear as it makes the ownership-relation explicit and parents in a inheritance context are often labelled *base*. At least i can't imagine a better name in a generic example - any suggestions?
Georg Fritzsche
@Georg, I usually call these like `outer` or `enclosing` or something, but that's just my taste. As I said - a nitpick.
Nikolai N Fetissov
A: 

This is an automagic, albeit possibly nonportable trick (worked on VC++ since 6.0 though). Class B has to be a member of class A for this to work.

#ifndef OUTERCLASS
#define OUTERCLASS(className, memberName) \
    reinterpret_cast<className*>(reinterpret_cast<unsigned char*>(this) - offsetof(className, memberName))
#endif 

class A
{
private:
    class B
    {
    public:
        void foobar() {
           A* pA = OUTERCLASS(A, m_classB);
           pA->foo();
        }
    } m_classB;
public:
    foo();
    bar();
};
Igor Zevaka
Thank you, Igor for respnding to my question and providing an example. You and Georg have almost similar implementation with a reference back to the outer class, however, I have selected Georg's response as it is cleaner.
Rahul
No worries, this is after all a pretty nasty looking hack. Having said that, it's been pretty reliable and it's kinda fun :)
Igor Zevaka