Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access a protected constructor from a friend function?

I created a class and I want to force anyone who's trying to construct an object, to use unique_ptr. To do that I thought of declaring the constructor protected and use a friend function that returns a unique_ptr. So here's an example of what I want to do:

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

I did some reading on friend functions and I understood that a friend function provides access to private/protected members of an object of a class.


Is there anyway I can make my example work?

Even without friend functions, my goal is to make the CreateA the only way for someone to create an object.

EDIT

I change the code a bit. I didn't mention that my class takes one template parameter. That makes things more complex apparently.

like image 588
TheCrafter Avatar asked Nov 24 '15 19:11

TheCrafter


People also ask

Can friend function access protected members?

friend functions A friend function is a function that isn't a member of a class but has access to the class's private and protected members.

What happens if a constructor is declared protected?

Protecting a constructor prevents the users from creating the instance of the class, outside the package. During overriding, when a variable or method is protected, it can be overridden to other subclass using either a public or protected modifier only. Outer class and interface cannot be protected.

Can friend access protected members C++?

A friend class can access both private and protected members of the class in which it has been declared as friend.

Can we use protected in constructor?

Modifiers public, protected and, private are allowed with constructors. We can use a private constructor in a Java while creating a singleton class.


2 Answers

You can do it this way :-

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

Output :-

5

If you don't want to use friend function you can make the function static & call it like this :-

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

EDIT :-

In reply to your edit I rewrote the program & it goes like this :-

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

Simple & easy !!! But remember you cannot instantiate the object of A. Good Luck !!!

like image 66
Ankit Acharya Avatar answered Oct 19 '22 00:10

Ankit Acharya


The other answers suggest using a static template function, which I agree is the best solution, because it is simpler.

My answer explains why your friend approach didn't work and how to use the friend approach correctly.


There are two problems in your original code. One is that make_unique is not actually a friend of A, so the call make_unique<A<T>>(myarg); does not have access to A's protected constructor. To avoid this , you can use unique_ptr<A<T>>(new A(myarg)) instead. Theoretically it would be possible to declare make_unique a friend but I'm not even sure of the right syntax for that.

The other issue is the template friends problem. Inside a class template, friend <function-declaration> actually declares a non-template friend.

The C++ FAQ suggests two possible workarounds. One of them is to define the friend function inline. However, in that case the function can only be found by argument-dependent lookup. But since the function does not take A<T> (or A<T> &) as argument, it can never be found this way. So this option is not viable to your situation -- it's more suited to operator overloading.

So the only fix is to declare (and optionally define) the template function before the class definition:

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

Note: It is possible to declare CreateA where I have defined it, and put the function definition later. However, the code I have posted works -- despite A not being defined when new A<T>(myarg) appears in the source -- because CreateA is not instantiated until it is called, at which point A will be defined.

like image 43
M.M Avatar answered Oct 19 '22 01:10

M.M