La fonction de membre de la classe imbriquée ne peut pas accéder à la fonction de la classe enclosée. Pourquoi?

StackOverflow https://stackoverflow.com/questions/3058267

  •  27-09-2019
  •  | 
  •  

Question

Veuillez consulter l'exemple de code ci-dessous:

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

Au sein de la classe A&B Implémentation:

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

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

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

Le compilateur signale l'appel à foo () dans la méthode foobar (). Plus tôt, j'avais foo () en tant que fonction de membre privé de la classe A, mais j'ai changé pour le public en supposant que la fonction de B ne peut pas le voir. Bien sûr, cela n'a pas aidé. J'essaie de réutiliser les fonctionnalités fournies par la méthode de A. Pourquoi le compilateur n'autorise-t-il pas cet appel de fonction? Comme je le vois, ils font partie de la même classe enclosante (a). Je pensais que le problème d'accessibilité pour les Meebers de classe imbriqués pour la classe de clôture dans les normes C ++ était résolu.

Comment puis-je réaliser ce que j'essaie de faire sans réécrire la même méthode (foo ()) pour b, qui gardant b imbriqué dans A?

J'utilise le compilateur VC ++ VER-9 (Visual Studio 2008). Merci de votre aide.

Était-ce utile?

La solution

foo() est une fonction membre non statique de A Et vous essayez de l'appeler sans instance.
La classe imbriquée B est une classe séparée qui n'a que des privilèges d'accès et n'a aucune connaissance particulière sur les instances existantes de A.

Si B a besoin d'accès à un A Vous devez lui faire référence, par exemple:

class A {
    class B {
        A& parent_;
    public:
        B(A& parent) : parent_(parent) {}
        void foobar() { parent_.foo(); }
    };
    B b_;
public:
    A() : b_(*this) {}
};

Autres conseils

Il s'agit d'une astuce automagique, bien que peut-être non portable (a cependant fonctionné sur VC ++ depuis 6.0). La classe B doit être membre de la classe A pour que cela fonctionne.

#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();
};

Si vous souhaitez réutiliser les fonctionnalités de A, vous devez hériter d'un NEST B Not B à l'intérieur.

Fondamentalement, ce que Georg Fritzsche a dit

#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;
}

Si vous décommentez le constructeur B par défaut, vous obtiendriez une erreur

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top