2014-12-18 5 views
13

Basierend auf dem folgenden answer ein aktuellen question nennen zu funktionieren, ich bin in der Lage einen Funktionszeiger zu verwenden, um die private Methode Foo<T>::foo() von einer anderen Klasse zu nennen Bar, wie unten dargestellt (siehe auch ideone)Able Zeiger verwenden private Methode einer externen Klasse

#include <iostream> 

template<typename T> 
struct Bar 
{ 
    typedef void (T::*F)(); 

    Bar(T& t_ , F f) : t(t_) , func(f) 
    { 
    } 

    void operator()() 
    { 
     (t.*func)(); 
    } 

    F func; 
    T& t; 
}; 

template<typename T> 
class Foo 
{ 
private: 
    void foo() 
    { 
     std::cout << "Foo<T>::foo()" << std::endl; 
    } 

public:  
    Foo() : bar(*this , &Foo::foo) 
    { 
     bar(); 
    } 

    Bar<Foo<T> > bar; 
}; 

int main() 
{ 
    Foo<int> foo; 
} 

Dies funktioniert auf MSVC 2013 und GCC 4.8.3. Ist es gültig?

+3

Sicher, warum sollte es nicht sein? Der Zugriff wurde überprüft, als der Zeiger zugewiesen wurde. – Deduplicator

+0

Das ist wirklich nicht anders als öffentlich zu werden: void buz() {foo(); } ' –

Antwort

7

Ja, es ist erlaubt, und es funktioniert.

C++ Programming by Bjarne Stroustoup

C++ vor Unfällen schützt eher als bewusste Umgehung (Betrug)

Sicher, können Sie nicht direkt/leicht private Methoden außerhalb der Klasse nennen, aber wenn man genug darum bemühen, , C++ wird es erlauben.

+0

Es gibt keine Umgehung hier beteiligt, es ist eine einfache Verwendung eines Zeigers. – Deduplicator

+0

@Deduplicator Umgehung gegen private Datenmitglieder. –

+0

@Deduplicator '(t. * Func)();' - Umgehung, privates Mitglied -> void foo(). Ich vermisse etwas? –

1

Ja, es ist gültig.

Bar.operator()() verwendet nur einen Zeiger und versucht nicht, einen Bezeichner mit einem privaten Zugriffsspezifizierer zu verwenden.
Es spielt keine Rolle, wie dieser Zeiger initialisiert wurde, solange er auf die richtige Funktion zeigt.

As an example, look at this:

#include <iostream> 
struct A { 
protected: 
    void hidden() { std::cout << "But I was hidden !?\n"; } 
}; 
struct B : A { 
    using A::hidden; // Making it public 
}; 
int main() { 
    B().hidden(); 
} 

Als beiseite, verwenden Sie nicht std::endl, wenn Sie wirklich den Strom spülen wollen, wie teuer ist.
Normalerweise genügt '\n'.

15

C++ Standard sagt

11,1 Ein Mitglied einer Klasse kann
(1.1) sein - privat; das heißt, sein Name kann nur von Mitgliedern und Freunden der Klasse verwendet werden, in der er deklariert ist.

d. H. Der Zugriffsspezifizierer wird auf den Namen und nicht auf den ausführbaren Code angewendet. Dies ist sinnvoll, wenn Sie darüber nachdenken, da Zugriffsspezifizierer ein kompilierbares Konstrukt sind.

+0

Ja, für das Standardangebot. – Deduplicator

+3

Es ist zu beachten, dass es die Wahl der Klasse 'Foo' ist, den Konstruktor von' Bar' mit dem Zeiger auf die Funktion zu versehen. Ohne diese Hilfe von innen wäre Bar nicht in der Lage, 'Foo :: foo()' von außen zu nennen. – cmaster

0

Es ist wichtig.

Header-Datei

class A; 
typedef int (A::*handler)(int x); 
struct handler_pair { 
    int code, 
    handler fn 
} 

class A { 
... 
private: 
    int onGoober(int x); 
    int onGomer(int x); 
}; 

Quelldatei

handler_pair handler_map[] = { 
    {0, &A::onGoober},   // these will complain about the method being private 
    {1, &A::onGomer} 
}; 

die handler_map auf ein statisches Element in der Klasse ändern und auf diese Weise die Initialisierung vermeidet die Beschwerde.

Wohin Sie die Adresse der Mitgliedsfunktion nehmen, ist wichtig.

Verwandte Themen