2015-11-24 7 views
8

Ho creato una classe e voglio forzare chiunque stia cercando di costruire un oggetto, per usare unique_ptr. Per farlo ho pensato di dichiarare il costruttore protected e utilizzare una funzione friend che restituisce un unique_ptr. Quindi, ecco un esempio di quello che voglio fare:Come posso accedere ad un costruttore protetto da una funzione amico?

template <typename T> 
class A 
{ 
public: 
    friend std::unique_ptr<A<T>> CreateA<T>(int myarg); 

protected: 
    A(int myarg) {} 
}; 

template <typename T> 
std::unique_ptr<A<T>> CreateA(int myarg) 
{ 
    // Since I declared CreateA as a friend I thought I 
    // would be able to do that 
    return std::make_unique<A<T>>(myarg); 
} 

Ho fatto qualche lettura sulla funzioni friend e ho capito che una funzione amico fornisce l'accesso ai membri privati ​​/ protetti di un oggetto di una classe.


Esiste comunque il mio esempio?

Anche senza funzioni friend, il mio obiettivo è quello di rendere il modo in cui l'CreateAsolo per qualcuno per creare un oggetto.

EDIT

cambio il codice un po '. Non ho detto che la mia classe prende un parametro di modello. Questo rende le cose più complesse in apparenza.

+1

correlati: http://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const – Brian

+0

Qual è lo scopo del metodo amico qui? Se il tuo unico obiettivo è impedire agli altri di usare il costruttore, è sufficiente renderlo privato o protetto (se vuoi ereditare questa classe in seguito) è sufficiente. –

+0

vedi anche "named constructor" –

risposta

3

Si può fare in questo modo: -

#include <iostream> 
#include <memory> 
using namespace std; 
class A 
{ 
    int arg; 
public: 
    friend unique_ptr<A> CreateA(int myarg); 
    void showarg() { cout<<arg; } 

protected: 
    A(int myarg): arg(myarg) {} 
}; 
unique_ptr<A> CreateA (int myarg) 
{ 
    return std::unique_ptr<A>(new A(myarg)); 
} 
int main() 
{ 
    int x=5; 
    unique_ptr<A> u = CreateA(x); 
    u->showarg(); 
    return 0; 
} 

uscita: -

5 

Se non si desidera utilizzare la funzione friend è possibile effettuare la funzione di chiamata di static & così: -

unique_ptr<A> u = A::CreateA(x); 
.210

EDIT: -

In risposta alla tua modifica ho riscritto il programma & va in questo modo: -

#include <iostream> 
#include <memory> 
using namespace std; 
template <typename T> 
class A 
{ 
    T arg; 
public: 
    static std::unique_ptr<A> CreateA(T myarg) 
    { 
     return std::unique_ptr<A>(new A(myarg)); 
    } 
    void showarg() 
    { 
     cout<<arg; 
    } 
protected: 
    A(T myarg): arg(myarg) {} 
}; 

int main() 
{ 
    int x=5; 
    auto u = A<int>::CreateA(x); 
    u->showarg(); 
    return 0; 
} 

semplice & facile !!! Ma ricorda che non è possibile creare un'istanza dello object of A. In bocca al lupo !!!

+0

Sembra funzionare ma avere un parametro template per 'classe A' rende le cose più complesse. Ho aggiornato la mia domanda per includerla. – TheCrafter

+0

Funziona con la tua modifica ma ho notato qualcosa di veramente strano! Se invece di restituire un 'unique_ptr' usando' new', faccio questo: 'return std :: make_unique (myarg)' Ricevo un errore. Non è strano? Voglio dire, pensavo che 'make_unique' chiamasse' new' e restituisse un 'unique_ptr'. Sono confuso. – TheCrafter

+0

'make_unique' usa la dichiarazione 'return unique_ptr (new T (...))' –

2

Creare una funzione statica che crea un'istanza del costruttore protetto.

#include<iostream> 
#include<string.h> 
#include<ctype.h> 
#include<math.h> 
#include <memory> 
using namespace std; 
template< typename T > 
class A 
{ 
public: 
    static void CreateA(int myarg, std::unique_ptr<A<T>>& objA, T t) { 
     std::unique_ptr<A<T>> objB(new A(myarg, t)); 
     objA = std::move(objB); 
    } 

protected: 
    A(int myarg, T t) { 
     m_t = t; 
    } 

private: 
    T m_t; 
}; 

int main() { 

    int myArg = 0; 
    std::unique_ptr<A<int>> anotherObjA; 
    A<int>::CreateA(myArg, anotherObjA, myArg); 


    return 0; 
} 
2

Le altre risposte suggeriscono di utilizzare una funzione di modello statico, che sono d'accordo è la soluzione migliore, perché è più semplice.

La mia risposta spiega perché l'approccio del tuo amico non ha funzionato e come utilizzare correttamente l'approccio amico.


Ci sono due problemi nel codice originale. Uno è che make_unique non è in realtà un amico di A, quindi la chiamata make_unique<A<T>>(myarg); non ha accesso al costruttore protetto di A. Per evitare questo, è possibile utilizzare unique_ptr<A<T>>(new A(myarg)) invece. Teoricamente sarebbe possibile dichiarare un amico make_unique ma non sono nemmeno sicuro della sintassi corretta per quello.

L'altro problema è the template friends problem.All'interno di un modello di classe, friend <function-declaration> dichiara effettivamente un amico non modello.

Le domande frequenti su C++ suggeriscono due possibili soluzioni. Uno di questi è definire la funzione amico in linea. Tuttavia, in tal caso, la funzione può trovare solo dalla ricerca dipendente dall'argomento. Ma poiché la funzione non accetta A<T> (o A<T> &) come argomento, non può mai essere trovata in questo modo. Quindi questa opzione non è fattibile per la tua situazione: è più adatta all'overloading dell'operatore.

Quindi l'unica soluzione è di dichiarare (ed eventualmente definire) la funzione di modello prima della definizione di classe:

#include <memory> 

template<typename T> 
class A; 

template <typename T> 
std::unique_ptr<A<T>> CreateA(int myarg) 
{ 
    return std::unique_ptr<A<T>>{new A<T>(myarg)}; 
} 

template <typename T> 
class A 
{ 
    friend std::unique_ptr<A<T>> CreateA <> (int myarg); 
//   refers to existing template ^^ 

protected: 
    A(int myarg) {} 
}; 

int main() 
{ 
    auto x = CreateA<int>(5); 
} 

Nota: E 'possibile dichiarare CreateA dove ho definito, e mettere la definizione di funzione dopo. Tuttavia, il codice che ho pubblicato funziona - nonostante A non venga definito quando new A<T>(myarg) appare nella sorgente - perché CreateA non viene istanziato fino a quando non viene chiamato, a quel punto verrà definito A.

+0

perché genera il codice errore se definiamo prima la classe e poi la funzione' amico' – Anwesha

+0

tu non c'è bisogno di menzionare il tipo, 'CreateA' lo deduce senza che tu menzioni in questo caso –

+0

@AnkitAcharya no, forse stai mentalmente mescolando questo codice con il codice nella tua risposta (che usa' T myarg' invece di 'int myarg') –

Problemi correlati