2015-11-24 5 views
8

Ich habe eine Klasse erstellt und möchte jeden, der ein Objekt erstellen möchte, dazu zwingen, unique_ptr zu verwenden. Dazu habe ich gedacht, den Konstruktor protected zu deklarieren und eine friend Funktion zu verwenden, die eine unique_ptr zurückgibt. Also hier ist ein Beispiel dafür, was ich tun möchte:Wie kann ich über eine Friend-Funktion auf einen geschützten Konstruktor zugreifen?

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

Ich habe einige Lesung zu Freund Funktionen und ich verstanden, dass ein Freund-Funktion Zugriff auf private/protected Mitglieder eines Objekts einer Klasse zur Verfügung stellt.


Gibt es trotzdem kann ich mein Beispiel arbeiten lassen?

Auch ohne Freund Funktionen, ist mein Ziel, die CreateA die nur Weg für jemanden ein Objekt zu erstellen.

EDIT

ich den Code ändern, um ein Bit. Ich habe nicht erwähnt, dass meine Klasse einen Template-Parameter benötigt. Das macht die Dinge anscheinend komplexer.

+1

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

+0

Was ist der Zweck der Freund Methode hier? Wenn Ihr Ziel nur darin besteht, andere davon abzuhalten, den Konstruktor zu verwenden, reicht es aus, ihn privat oder geschützt zu machen (wenn Sie diese Klasse später erben wollen). –

+0

siehe auch "named constructor" –

Antwort

3

Sie können es auf diese Weise tun: -

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

Ausgang: -

5 

Wenn Sie nicht friend Funktion verwenden möchten, können Sie die Funktion static & Anruf es ist so: -

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

: -

In Antwort auf Ihre bearbeiten schrieb ich das Programm & es so geht: -

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

Einfach & einfach !!! Aber denken Sie daran, dass Sie die object of A nicht instanziieren können. Viel Glück !!!

+0

Das scheint zu funktionieren, aber ein Template-Parameter für 'Klasse A' macht Dinge komplexer. Ich habe meine Frage aktualisiert, um das zu berücksichtigen. – TheCrafter

+0

Es funktioniert mit deinem Schnitt, aber ich habe etwas wirklich seltsames bemerkt! Wenn ich anstelle von 'unique_ptr' das' new' verwende, mache ich das: 'return std :: make_unique (myarg)' Ich bekomme einen Fehler. Ist das nicht seltsam? Ich meine, ich dachte 'make_unique' nennt sich nur' new' und gibt'unique_ptr' zurück. Ich bin verwirrt. – TheCrafter

+0

'make_unique' verwendet die' return unique_ptr (neue T (...)) 'Anweisung –

2

Erstellen Sie eine statische Funktion, die den geschützten Konstruktor instanziiert.

#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

Die anderen Antworten schlagen vor, eine statische Template-Funktion zu verwenden, der ich zustimme, ist die beste Lösung, weil es einfacher ist.

Meine Antwort erklärt, warum Ihr Freund Ansatz nicht funktioniert und wie Sie den Freund Ansatz richtig verwenden.


Es gibt zwei Probleme in Ihrem ursprünglichen Code. Einer ist, dass make_unique ist eigentlich kein Freund von A, so dass der Anruf make_unique<A<T>>(myarg); keinen Zugriff auf A geschützten Konstruktor hat. Um dies zu vermeiden, können Sie stattdessen unique_ptr<A<T>>(new A(myarg)) verwenden. Theoretisch wäre es möglich, einen Freund als make_unique zu deklarieren, aber ich bin mir nicht einmal sicher, welche Syntax dafür richtig ist.

Das andere Problem ist the template friends problem.Innerhalb einer Klassenvorlage deklariert friend <function-declaration> tatsächlich einen Freund ohne Vorlage.

Die C++ - FAQ schlägt zwei mögliche Problemumgehungen vor. Einer von ihnen ist definieren die Freund-Funktion inline. In diesem Fall kann jedoch die Funktion nur durch argumentabhängiges Nachschlagen gefunden werden. Aber da die Funktion A<T> (oder A<T> &) nicht als Argument verwendet, kann sie niemals auf diese Weise gefunden werden. Diese Option ist also für Ihre Situation nicht geeignet - sie ist eher für das Überladen von Operatoren geeignet.

So ist die einzige Lösung ist, zu erklären (und definieren optional), um die Template-Funktion vor der Klassendefinition:

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

Hinweis: Es ist möglich, CreateA zu erklären, wo ich es definiert haben, und die Funktionsdefinition setzen später. Der Code, den ich gepostet habe, funktioniert jedoch - trotz A, der nicht definiert wird, wenn new A<T>(myarg) in der Quelle angezeigt wird - weil CreateA nicht instanziiert wird, bis es aufgerufen wird. Dann wird A definiert.

+0

warum wirft der Code Fehler, wenn wir die Klasse zuerst definieren und dann die' Freund' Funktion – Anwesha

+0

Sie muss nicht den Typ erwähnen, 'CreateA' leitet es ab, ohne dass du in diesem Fall –

+0

@AnkitAcharya no notierst, vielleicht machst du diesen Code mental mit dem Code in deiner Antwort (der' T myarg' verwendet) anstelle von "int myarg") –

Verwandte Themen