2014-12-18 13 views
13

sulla base dei seguenti answer un recente question, sono in grado di utilizzare un puntatore a funzione, al fine di chiamare il metodo privato Foo<T>::foo() da un'altra classe Bar, come mostrato di seguito (vedi anche ideone)In grado di utilizzare puntatore a funzione di chiamare il metodo privato di una classe esterna

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

Questo funziona su MSVC 2013 e GCC 4.8.3. È valido?

+3

Certo, perché non dovrebbe essere? L'accesso è stato controllato quando il puntatore è stato assegnato. – Deduplicator

+0

Questo non è affatto diverso dall'avere 'public: void buz() {foo(); } ' –

risposta

7

Sì, è consentito e funziona.

C++ Programming by Bjarne Stroustoup

C++ protegge contro gli infortuni piuttosto che elusione deliberata (frode)

Certo, si può non direttamente/facilmente chiamare i metodi privati ​​al di fuori della classe, ma se si stanno facendo sforzi sufficienti , Il C++ lo permetterà.

+0

Qui non vi è alcun aggiramento, è un uso diretto di un puntatore. – Deduplicator

+0

@Deduplicator aggirando contro membri dati privati. –

+0

@Deduplicator '(t. * Func)();' - elusione, membro privato -> void foo(). Mi manca qualcosa? –

1

Sì, è valido.

Bar.operator()() utilizza solo un puntatore, non tenta di utilizzare un identificatore con identificatore di accesso privato.
Non importa in che modo il puntatore è stato inizializzato, purché punti alla funzione corretta.

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

Per inciso, non usare std::endl a meno che non si vuole veramente per irrigare la corrente, in quanto questo è costoso.
Normalmente '\n' è sufficiente.

15

standard di C++ dice

11,1 Un membro di una classe può essere
(1.1) - privato; cioè, il suo nome può essere usato solo da membri e amici della classe in cui è dichiarato.

ovvero lo specificatore di accesso viene applicato al nome, non al codice eseguibile. Questo ha senso se ci pensate, dal momento che gli specificatori di accesso sono un costrutto in fase di compilazione.

+0

Sì, per la quota standard. – Deduplicator

+3

Si noti che è la scelta della classe 'Foo' di fornire il costruttore di' Bar' con il puntatore alla funzione. Senza questo aiuto dall'interno, Bar non sarebbe in grado di chiamare "Foo :: foo()" dall'esterno. – cmaster

0

Non importa.

Header File

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

file di origine

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

Modifica della handler_map a un membro statico della classe e l'inizializzazione in questo modo evita la denuncia.

Dove si prende l'indirizzo della funzione membro è importante.