Why Is Protected Constructor Raising an Error This This Code

Why is protected constructor raising an error this this code?

This has nothing to do with constructors specifically. This is just how protected access works.

The way protected access specifier works, it allows the derived class B to access the contents of an object of base class A only when that object of class A is a subobject of class B. That means that the only thing you can do in your code is to access the contents of A through B: you can access the members of A through a pointer of type B * (or a reference of type B &). But you cannot access the same members through a pointer of type A * (or reference A &).

Consider the following example

class A {
protected:
int i;
};

class B : A {
void foo() {
i = 0; // OK
this->i = 0; // OK

B *pb = this;
pb->i = 0; // OK

A *pa = this;
pa->i = 0; // ERROR

((A *) this)->i = 0; // ERROR
}
};

In the above B::foo, you can access base member A::i by using just plain i syntax. This is equivalent to using this->i syntax. Both will work, because the pointer this has type B *, i.e. you are accessing A::i thorough a pointer of type B *. This is exactly what the protected access specifier is supposed to allow. The access through pb pointer works for the very same reason.

However, when you "convert" this pointer to type A *, you can no longer access A::i through that new pointer, even though you are still trying to access they very same member as before.

When applied to constructors, the protected access specifier has a very specific effect: a protected constructor can only be used to initialize base-class subobjects. It cannot be used to initialize standalone objects (which is what you were trying to do). In other words, protected constructors are another way to implement the concept of abstract class in C++ (along with pure virtual methods). If the constructors of your class are protected, then your class is effectively abstract. You can't use it to define independent objects "from outside". (Of course, the above does not apply within friends, as well as within the class itself).

Forbid users to create objects but allow some classes

In addition to user2913094's answer:

If giving B full friendship just to allow construction seems unacceptable, you can add a constructor that requires a construction token, which can only be obtained by B:

class A {
public:
class ConstructionToken {
private:
ConstructionToken();
friend class B;
};

A(ConstructionToken const&);
protected:
A();
};

Note that the token class is completely empty, but since only B can access its private constructor, that essentially prevents the user of invoking A's public constructor directly.

This allows for more fine-grained access control, but has the disadvantage that it requires introducing an additional constructor overload on A.

Eclipse shows an error when trying to use protected constructor in a subclass located in other package

This is fun so let me try to summarize it. see JLS#6.6.1

protected can qualify a constructor or a member of a class.

"member" includes field/method (static/instance), nested class/interface (static/inner)

class A {
protected int f
protected void m(){}
protected class X{}
protected interface Y{}

First, to access a protected constructor/member, the enclosing class (e.g. A) must be accessible. Assume that's the case, then --

--Inside the package --

A protected constructor or member is accessible anywhere within the same package.

--Outside the package --

A protected constructor is only accessible within subclass constructors, either as a super() call, or as an anonymous class instantiation.

A protected static field/method, nested class/interface is accessible anywhere within subclass bodies.


A protected instance field/method is more complex --

  • protected "m" is defined in a class A
  • obj.m is accessed in class B (outside A's package)
  • obj 's type is C

The access obj.m is granted only if B is subclass of A, and C is subclass of B or C is B.

super.m is always allowed; however, it's unclear how JLS frames the issue. It seems that the access should be treated the same as this.m, therefore access is allowed.

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

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 !!!

Instance subclass field using parent protected constructor

Why it's impossible to create instance of A in class B using class A
protected constructor?

You can't call a protected constructor using the new modifier because the purpose of a protected constructor is that it can only be called from a derived classes point of view, thus not visible from the "outside".

The compiler doesn't infer the call to new A() is being done from an instance of B. That is why the constructor syntax is available, to guarantee a convention of how to call base constructors.

You can call A constructor when declaring a constructor for B :

public B(string foo) : base(foo)

This is what actually is being done on your behalf for a default constructor. For example:

public class A {}
public class B : A
{
public B() {}
}

Will yield the following IL:

// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x205a
// Code size 7 (0x7)
.maxstack 8

IL_0000: ldarg.0
IL_0001: call instance void A::.ctor() <--- This.
IL_0006: ret
} // end of method B::.ctor

One hackish way (I would avoid doing that) is to create such an instance can be achieved with Activator.CreateInstance overload which accepts a bool flag indicating the constructor is non-public:

var b = (B)Activator.CreateInstance(typeof(B), nonPublic: true);

Why the constructor of std::ostream is protected?

I'll admit that I don't understand it either. I can't find any
default constructor at all for std::istream, and I would think
you would want one if you want to create a bidirectional stream,
because of the strange way std::ios_base works: the
constructor does not initialize anything, but the derived
class must call std::ios_base::init explicitly in its
constructor. When multiple inheritance is involved (i.e.
bidirectional IO, where the class derives from both
std::istream and std::ostream), I would expect only the most
derived class to call std::ios_base::init. (In
std::iostream, std::ios_base::init will be called twice.)
In fact, before looking it up in the standard, I was about to
answer that the default constructor was protected, because it
didn't call std::ios_base::init, and using it directly, rather
than in a derived class, would result in an uninitialized
stream.

Anyhow, your immediate problem has a simple solution:

std::ostream out( NULL );

Also: the function you need to set up its sink later is the
non-const version of rdbuf(), not copyfmt(). rdbuf() is
used to read and to set the pointer to the streambuf,
copyfmt() copies the formatting flags, but does not touch
the pointer to streambuf.

So you can do things like:

std::ostream out( NULL );
// ...
std::filebuf fileBuffer;
if ( filenameGiven ) {
fileBuffer.open( filename.c_str(), std::ios_base::out );
}
if ( fileIsOpen() ) {
out.rdbuf( &fileBuffer );
} else {
out.rdbuf( std::cout.rdbuf() );
}

(I do this a lot. In fact, I thought that it was the usual
idiom when you didn't know up front whether to output to a file
or to std::cout.)

EDIT:

And yet another correction: the non-const version of rdbuf calls clear(),
so you don't have to. (I knew I'd done this without calling clear(), but
when I saw that init set badbit...)

Anyhow: the summary is: it's usually preferrable to pass a pointer to a valid
streambuf to the constructor of std::ostream, but if you can't, it's
perfectly valid to pass a null pointer, and set a valid pointer later using
rdbuf(). And the answers which say otherwise are simply wrong.

Should this code fail to compile in C++17?

clang is correct here. Here's a reduced example:

struct B {
protected:
B() { }
};

struct D : B { };

auto d = D{};

In C++14, D is not an aggregate because it has a base class, so D{} is "normal" (non-aggregate) initialization which invokes D's default constructor, which in turn invokes B's default constructor. This is fine, because D has access to B's default constructor.

In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual). D is now an aggregate, which means that D{} is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B's constructor (it is protected), so we cannot invoke it, so it is ill-formed.


Fear not, the fix is easy. Use parentheses:

auto d = D();

This goes back to invoking D's default constructor as before.

Mocking Protected Constructor

You have to Prepare ExtendedClass for Test and not SuperClass.

change

 @PrepareForTest({SuperClass.class})

PowerMockito.suppress(PowerMockito.constructor(SuperClass.class, String.class, Integer.class));

to

 @PrepareForTest({ExtendedClass.class})

PowerMockito.suppress(PowerMockito.constructor(ExtendedClass.class, String.class, Integer.class));


Related Topics



Leave a reply



Submit