Функция-член вложенного класса не может получить доступ к функции включающего класса. Зачем? - PullRequest
18 голосов
/ 17 июня 2010

Пожалуйста, посмотрите пример кода ниже:

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

В реализации класса A & B:

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, но я переключился на public, предполагая, что функция B не может ее видеть. Конечно, это не помогло. Я пытаюсь повторно использовать функциональность, предоставляемую методом А. Почему компилятор не позволяет этот вызов функции? На мой взгляд, они являются частью одного класса (A). Я думал, что проблема доступности для вложенных классов классов для включения класса в стандарты C ++ была решена.

Как мне добиться того, что я пытаюсь сделать, не переписывая тот же метод (foo ()) для B, который сохраняет B вложенным в A?

Я использую компилятор VC ++ ver-9 (Visual Studio 2008). Спасибо за вашу помощь.

Ответы [ 4 ]

20 голосов
/ 17 июня 2010

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) {}
};
1 голос
/ 17 июня 2010

Это автоматическая, хотя, возможно, и непереносимая уловка (хотя работала на VC ++ начиная с 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();
};
0 голосов
/ 15 мая 2012

В основном то, что сказал Георг Фрицше

#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 по умолчанию, вы получите ошибку

0 голосов
/ 17 июня 2010

Если вы хотите повторно использовать функциональность из A, тогда вы должны наследовать от A, а не от гнезда B внутри него.

...