2015-11-24 6 views
8

Создал класс, и я хочу заставить всех, кто пытается построить объект, использовать unique_ptr. Для этого я подумал об объявлении конструктора protected и использовать функцию friend, которая возвращает unique_ptr. Так вот пример того, что я хочу сделать:Как получить доступ к защищенному конструктору из функции friend?

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

Я сделал некоторое чтение на других функциях, и я понял, что функция друг обеспечивает доступ к частному/защищенных членам объекта класса.


Есть ли в любом случае я могу сделать свой пример работой?

Даже без функций друзей моя цель состоит в том, чтобы сделать CreateAтолько способом для кого-то создать объект.

EDIT

я изменить код немного. Я не упоминал, что мой класс принимает один параметр шаблона. Это делает вещи более сложными, по-видимому.

+1

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

+0

Какова цель метода друга здесь? Если ваша единственная цель - заставить других использовать конструктор, просто сделать его закрытым или защищенным (если вы хотите наследовать этот класс позже) достаточно. –

+0

см. Также «named constructor» –

ответ

3

Вы можете сделать это следующим образом: -

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

Выход: -

5 

Если вы не хотите использовать функцию friend вы можете сделать функцию static & вызова это примерно так: -

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

EDIT: -

В ответ на ваши изменения я переписал программу & это выглядит следующим образом: -

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

Простой & легко !!! Но помните, что вы не можете создать экземпляр object of A. Удачи !!!

+0

Это похоже на работу, но наличие параметра шаблона для класса «А» делает вещи более сложными. Я обновил свой вопрос, чтобы включить это. – TheCrafter

+0

Он работает с вашим редактированием, но я заметил что-то действительно странное! Если вместо возврата 'unique_ptr' с помощью' new', я делаю это: 'return std :: make_unique (myarg)' Я получаю сообщение об ошибке. Разве это не странно? Я имею в виду, я думал, что 'make_unique' просто вызывает' new' и возвращает 'unique_ptr'. Я запутался. – TheCrafter

+0

'make_unique' использует' return unique_ptr (новый T (...)) 'statement –

2

Создайте статическую функцию, которая создает экземпляр защищенного конструктора.

#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

Другие ответы предлагают использовать статическую функцию шаблона, которую я согласен - лучшее решение, потому что оно проще.

Мой ответ объясняет, почему ваш друг не работал и как правильно использовать подход друзей.


В исходном коде есть две проблемы. Один из них заключается в том, что make_unique на самом деле не является другом A, поэтому вызов make_unique<A<T>>(myarg); не имеет доступа к защищенному конструктору A. Чтобы этого избежать, вместо этого вы можете использовать unique_ptr<A<T>>(new A(myarg)). Теоретически можно было бы объявить make_unique другом, но я даже не уверен в правильном синтаксисе для этого.

Другая проблема: the template friends problem.Внутри шаблона класса friend <function-declaration> фактически объявляет друга без шаблонов.

Часто задаваемые вопросы по C++ предлагают два возможных обходных пути. Один из них - определяет функцию друга inline. Тем не менее, в этом случае функция может только быть найдена зависимым от аргумента поиска. Но так как функция не принимает A<T> (или A<T> &) в качестве аргумента, ее никогда нельзя найти таким образом. Таким образом, этот вариант не подходит для вашей ситуации - он больше подходит для перегрузки оператора.

Таким образом, единственное исправление объявить (и, возможно, определить) функцию шаблона перед определением класса:

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

Примечание: Можно объявить CreateA где я определил его, и поместить определение функции позже. Однако код, который я опубликовал, работает, несмотря на то, что A не определен, когда в источнике появляется new A<T>(myarg) - потому что CreateA не создается до его вызова, и в этом пункте будет определено значение A.

+0

, почему ошибка при вызове кода, если мы определим первый класс, а затем функцию' friend' – Anwesha

+0

, вы не нужно упоминать тип, 'CreateA' выводит его без упоминания в этом случае –

+0

@AnkitAcharya нет, это не так, возможно, вы мысленно смешиваете этот код с кодом в своем ответе (который использует' T myarg' вместо 'int myarg') –

 Смежные вопросы

  • Нет связанных вопросов^_^