Nested Class member function can't access function of enclosing class. Why?
Please see the example code below:
class A
{
private:
class B
{
public:
foobar();
};
public:
foo();
bar();
};
Within class A & B im开发者_开发技巧plementation:
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.
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) {}
};
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();
};
Basically what Georg Fritzsche said
#include <iostream>
#include <cstring>
using namespace std;
class A
{
private:
class B
{
A& parent_;
public:
//B(); //uncommenting gives error
~B();
B(A& parent) : parent_(parent) {}
void foobar()
{
parent_.foo();
cout << "A::B::foo()" <<endl;
}
const std::string& foobarstring(const std::string& test) const
{
parent_.foostring(test); cout << "A::B::foostring()" <<endl;
}
};
public:
void foo();
void bar();
const std::string& foostring(const std::string& test) const;
A();
~A(){};
B b_;
};
//A::B::B() {}; //uncommenting gives error
A::B::~B(){};
A::A():b_(*this) {}
void A::foo()
{
cout << "A::foo()" <<endl;
}
const std::string& A::foostring(const std::string& test) const
{
cout << test <<endl;
return test;
}
void A::bar()
{
//some code
cout << "A::bar()" <<endl;
foo();
//more code
}
int main(int argc, char* argv[])
{
A a;
a.b_.foobar();
a.b_.foobarstring("hello");
return 0;
}
If you uncomment the default B constructor you would get an error
If you want to reuse functionality from A then you should inherit from A not nest B inside it.
Combining Igor Zevaka's and enthusiasticgeek's answers. Also, using reinterpret_cast for calculating offset (If you create class member variable using new keyword):
#include <iostream>
#include <cstring>
using namespace std;
template < typename T, typename U > constexpr size_t offsetOf(U T:: *member)
{
return (char*) &((T*) nullptr->*member) - (char*) nullptr;
}
class A
{
private:
class B
{
public:
B(string message);
~B();
void foobar()
{
A *pA = reinterpret_cast<A*> (reinterpret_cast< unsigned char*> (this) - offsetOf(&A::b_));
pA->foo();
pA->bar();
std::cout << "DONE!";
}
};
public:
void foo();
void bar();
A();
~A() {};
B* b_ = new B("Hello World!");
};
A::A()
{
cout << "A constructor\n";
};
A::B::B(string message) {
cout << "B constructor\n";
cout << "Message = " << message << "\n";
};
A::B::~B() {};
void A::foo()
{
cout << "A::foo()" << endl;
}
void A::bar()
{
cout << "A::bar()" << endl;
foo();
}
int main(int argc, char *argv[])
{
A* a = new A();
a->b_->foobar();
return 0;
}
Output:
B constructor
Message = Hello World!
A constructor
A::foo()
A::bar()
A::foo()
DONE!
References:
https://stackoverflow.com/a/10607424/9524565
https://stackoverflow.com/a/3058382/9524565
https://stackoverflow.com/a/20141143/9524565
精彩评论