Вложенная функция-член класса не может получить доступ к функции включения класса. Зачем?
См. пример кода ниже:
class A
{
private:
class B
{
public:
foobar();
};
public:
foo();
bar();
};
В реализациях класса А и В:
A::foo()
{
//do something
}
A::bar()
{
//some code
foo();
//more code
}
A::B::foobar()
{
//some code
foo(); //<<compiler doesn't like this
}
Компилятор помещает вызов foo() в метод foobar(). Раньше у меня была foo() как функция частного члена класса A, но была изменена на общественность, предполагая, что функция B не может ее видеть. Конечно, это не помогло. Я пытаюсь повторно использовать функциональность, предоставляемую методом A. Почему компилятор не разрешает вызов этой функции? Как я вижу, они являются частью того же охватывающего класса (A). Я думал, что проблема доступности для вложенных классов классов для включения класса в стандарты С++ была решена.
Как я могу достичь того, что я пытаюсь сделать, не переписывая тот же метод (foo()) для B, который удерживает B вложенным в A?
Я использую VС++ компилятор ver-9 (Visual Studio 2008). Благодарим вас за помощь.
Ответы
Ответ 1
foo()
является нестатической функцией-членом A
, и вы пытаетесь вызвать ее без экземпляра.
Вложенный класс B
является отдельным классом, который имеет только некоторые привилегии доступа и не имеет специальных знаний о существующих экземплярах A
.
Если B
нужен доступ к A
, вы должны указать ему ссылку, например:
class A {
class B {
A& parent_;
public:
B(A& parent) : parent_(parent) {}
void foobar() { parent_.foo(); }
};
B b_;
public:
A() : b_(*this) {}
};
Ответ 2
Это автоматический, хотя и возможно непереносимый трюк (работает на VС++ с 6.0). Класс B должен быть членом класса A для этого.
#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();
};
Ответ 3
Если вы хотите повторно использовать функциональность из A, тогда вы должны наследовать от A, а не внутри B.
Ответ 4
В принципе, что сказал Георг Фрицче
#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;
}
Если вы раскомментируете конструктор по умолчанию B, вы получите сообщение об ошибке