2010-06-17 41 views
15

Bitte beachten Sie die folgende Beispielcode:Die Memberfunktion der geschachtelten Klasse kann nicht auf die Funktion der umschließenden Klasse zugreifen. Warum?

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

Innerhalb der Klasse A & B Implementierung:

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

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

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

Die Compiler-Flags der Aufruf von foo() innerhalb der Methode foobar(). Zuvor hatte ich foo() als private Member-Funktion der Klasse A, änderte es aber in die Öffentlichkeit, wobei ich annahm, dass die Funktion von B es nicht sehen kann. Natürlich hat es nicht geholfen. Ich versuche, die von A's Methode zur Verfügung gestellte Funktionalität wiederzuverwenden. Warum erlaubt der Compiler diesen Funktionsaufruf nicht? Wie ich es sehe, sind sie Teil derselben umschließenden Klasse (A). Ich dachte, dass das Problem mit der Barrierefreiheit für Klassenverantwortliche für das Einschließen von Klassen in C++ - Standards gelöst wurde.

Wie kann ich erreichen, was ich versuche, ohne die gleiche Methode (foo()) für B zu schreiben, die B in A geschachtelt hält?

Ich verwende VC++ Compiler ver-9 (Visual Studio 2008). Danke für Ihre Hilfe.

Antwort

14

foo() ist eine nicht statische Elementfunktion von A und Sie versuchen, es ohne eine Instanz aufzurufen.
Die verschachtelte Klasse B ist eine separate Klasse, die nur einige Zugriffsrechte besitzt und keine speziellen Kenntnisse über vorhandene Instanzen von A besitzt.

Wenn B Bedarf den Zugriff auf eine A Sie haben es ihm einen Verweis zu geben, z.B .:

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

+1, nur ein Nitpick - "Elternteil" ist wahrscheinlich nicht der beste Name für Member-Variable hier - leichte Verwirrung mit Vererbung. –

+1

Ich wollte nur erwähnen, dass es einen sehr guten Entwurfsgrund für die verschachtelte Klasse B gab, einen Verweis auf Klasse A zu haben. – manifest

+0

Vielen Dank für die Erklärung mit Beispiel. Der C++ - Standard 11.8, von dem ich vermutete, dass er sich geändert hat, spricht über den Klassenzugriff von verschachtelten Klassen. Ich weiß, dass gcc den Zugriff durch geschachtelte Klasse erlaubt (ich bin mir sicher), aber MS VC Compiler nicht. Hmm, interessant. – Rahul

0

Wenn Sie die Funktionalität von A wiederverwenden möchten, sollten Sie von A nicht nest B innerhalb davon erben.

+1

Ich bin nicht der fucntionality von A in B erstreckt, so gibt es keine Notwendigkeit, zum Erben von B von A. Auch möchte ich B vor den Benutzern der Klasse A versteckt halten. – Rahul

1

Dies ist ein Automagic, wenn auch vielleicht nicht portierbar Trick (arbeitete an VC++ seit 6.0 obwohl). Klasse B muss Mitglied der Klasse A sein, damit dies funktioniert.

#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

Vielen Dank, Igor für die Beantwortung meiner Frage und ein Beispiel. Sie und Georg haben eine ähnliche Implementierung mit einem Verweis auf die äußere Klasse, jedoch habe ich Georgs Antwort ausgewählt, da sie sauberer ist. – Rahul

+0

Keine Sorge, das ist schließlich ein ziemlich hässlich aussehender Hack. Nachdem das gesagt wurde, ist es ziemlich zuverlässig und es macht Spaß :) –

0

Im Grunde, was Georg Fritzsche sagte

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

Wenn Sie den Standard B Konstruktor Kommentar- würden Sie einen Fehler

+0

Ich habe den Fehler nicht bekommen. – cbinder

+0

@cbinder versuchen, 'A :: B :: B() {};' auch zu kommentieren – enthusiasticgeek

Verwandte Themen