I have the following two classes.
Class A
{
proctected:
A(){}
};
Class B
{
push_new_A_into_v();
vector<A> v;
};
The function
push_new_A_into_v();
will not compile since A's constructor is protected. To make B inherit from A will not help since the method create a completely new A(Why is protected constructor raising an error this this code?).
The reason A's constructor is protected is to make users unable to create an object of type A.
How can I make it possible for the method to work while users is still unable to create objects of type A?
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.
class A {
friend class B;
...
Related
One question about protected constructor. I learnt that the protected constructor can be used in the derived class. How ever, I found the code below has an error. Why does it happen like this?
class A
{
protected:
A(){}
};
class B: public A {
public:
B() {
A* f=new A(); // Why it is not working here
}
};
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).
When a base class has a protected constructor, you can't instantiate the class directly. But you can do this to call the constructor from the base class constructor:
class A {
protected:
A() {}
};
class B: public A {
public:
B() : A() // allowed to access constructor like this
{
A* f = new A(); // Not allowed to access constructor like this!
}
};
A direct call to the constructor as shown below gives you the following error with gcc version 4.1.2:
A* f = new A(); // Not allowed to access constructor like this!
test.cpp:4: error: A::A() is protected
However, you this call to the constructor gives no errors:
B() : A() // allowed to access constructor like this
The reason behind this is that the second call accesses the A() constructor through inheritance, which is allowed. However, this tries to explicitly create a new instance of A() by calling the constructor directly:
A* f = new A(); // Not allowed to access constructor like this!
This might seem unintuitive, as B should be able to access A's constructor because B inherits from A. However, if you declare a constructor protected in C++, you can't create an instance of that class except through inheritance or a friend relationship.
Let me put my answer in steps:
1) Constructors don't get Inherited and that why in derived class, they can't be over ridden.
2) Constructors are invoked and not called.
3) If you have declared a simple function in A say protected void print() and then tried calling it in B, It would have worked. This happens bcoz, B has inherited this function.
4) When you do something like this b : a(), you are invoking the constructor and that's allowed.
5) Try making B a friend class of A and then run and see if it works.
Hope this helps.
I had the same question as this, and this link make me clear.
cppreference says like this:
Protected members form the interface for the derived classes (which is
distinct from the public interface of the class).
A protected member of a class Base can only be accessed
1) by the members and friends of Base
2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)
I am learning about inheritance right now, and there is one thing I haven't found a solid answer on. If I have three classes one being a super and two subclass, would my subclasses need a default constructor if they inherit the same fields? Class b doesn't have a default constructor because it inherits its fields from A, where as class c has different fields, therefore it would need its own default constructor.
class A {
private:
int a;
int b;
public:
A();
A(int, int);
};
class B: public A {
public:
B(int, int);
};
class C : public A {
private:
int c;
public:
C();
C(int, int);
};
anything is greatly appreciated.
If [irrelevant], would my subclasses need a default constructor if [irrelevant]?
That depends on how your subclasses are used. If – and only if – you need to construct an instance of your class without providing construction parameters, then that class needs a default constructor. Whether or not you need to explicitly define (or forward via using) a default constructor depends on whether or not other constructors are defined, and on whether or not that constructor has something non-trivial to do. This topic should have been covered long before inheritance.
There is, however, a new caveat when inheritance enters the picture. Since I cannot tell if you use member initialization lists, I recommend reading No Matching Function Call to Base class. If you do not use member initialization lists, your derived classes will construct their bases without construction parameters. However, note that it is usually better to address this situation by using initialization lists rather than adding a default constructor.
Class b doesn't have a default constructor because it inherits its fields from A,
No, class B doesn't have a default constructor because it defines a non-default constructor. The non-default constructor prevents the compiler from supplying a default constructor. If your code successfully compiles, one can conclude that B does not need a default constructor.
where as class c has different fields, therefore it would need its own default constructor.
Whether or not a class has fields is irrelevant to "need". (Fields may make it more likely that an explicit default constructor is appropriate since there might be data to initialize, but their mere existence does not dictate a need.)
A class should have a default constructor if you intend for calling code to be able to use a default constructor and create an instance of the class without passing additional arguments to it. B won't automatically get A's default constructor just because B adds no additional member variables.
B won't automatically have a default constructor just because A has one and B doesn't have any new variables. If you want to forward A's default constructor, you can do so with a using declaration like so:
class A {
private:
int a;
int b;
public:
A();
A(int, int);
};
class B: public A {
public:
using A::A; // All of A's constructors are now publically usable as B constructors
};
Note that I removed the declaration B(int, int); because the using declaration brings both constructors forward from A. If you want B(int, int); to do something different than A(int, int);, you can declare B(int, int); alongside the using declaration and the more derived constructor will shadow the inherited constructor.
One question about protected constructor. I learnt that the protected constructor can be used in the derived class. How ever, I found the code below has an error. Why does it happen like this?
class A
{
protected:
A(){}
};
class B: public A {
public:
B() {
A* f=new A(); // Why it is not working here
}
};
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).
When a base class has a protected constructor, you can't instantiate the class directly. But you can do this to call the constructor from the base class constructor:
class A {
protected:
A() {}
};
class B: public A {
public:
B() : A() // allowed to access constructor like this
{
A* f = new A(); // Not allowed to access constructor like this!
}
};
A direct call to the constructor as shown below gives you the following error with gcc version 4.1.2:
A* f = new A(); // Not allowed to access constructor like this!
test.cpp:4: error: A::A() is protected
However, you this call to the constructor gives no errors:
B() : A() // allowed to access constructor like this
The reason behind this is that the second call accesses the A() constructor through inheritance, which is allowed. However, this tries to explicitly create a new instance of A() by calling the constructor directly:
A* f = new A(); // Not allowed to access constructor like this!
This might seem unintuitive, as B should be able to access A's constructor because B inherits from A. However, if you declare a constructor protected in C++, you can't create an instance of that class except through inheritance or a friend relationship.
Let me put my answer in steps:
1) Constructors don't get Inherited and that why in derived class, they can't be over ridden.
2) Constructors are invoked and not called.
3) If you have declared a simple function in A say protected void print() and then tried calling it in B, It would have worked. This happens bcoz, B has inherited this function.
4) When you do something like this b : a(), you are invoking the constructor and that's allowed.
5) Try making B a friend class of A and then run and see if it works.
Hope this helps.
I had the same question as this, and this link make me clear.
cppreference says like this:
Protected members form the interface for the derived classes (which is
distinct from the public interface of the class).
A protected member of a class Base can only be accessed
1) by the members and friends of Base
2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)
I have a class (class A) which inherits another class (class B).
class A: public B
Class B disabled copy construct and assignment operator (due to not allow a copy).
private:
B(const B&);
B& operator=(const B&);
My question is that should I also disable copy construct and assignment operator in the derived class as well or is it okay if I did not define both.
Subclasses should have the same or stricter [preconditions, post conditions and invariants] than their parent classes. This is the Liskov Substitution Principle. So, you should not re-enable copy construction etc/whatever in the derived class, since you will be loosening the contract of the base class.
If you find you need to do it (or would really like to do it), then it may be a sign that you need to rethink your design.
The question is rather, should you re-enable it. If any base or member is noncopyable, your class will be noncopyable by default. Generally, you won't want to remove it, because it will be difficult or impossible to give it reasonable semantics. But there are notable exceptions: if the base class is abstract, for example, you may want to enable the copy constructor (but not assignment) in the derived class in order to support cloning.
Disallowing copy-constructor and assignment operator of base class will cause that the copy-constructor and assignment operator of derived class won't be usable as well:
class B {
public:
B() { }
private:
B(const B&);
B& operator=(const B&);
};
class A : public B { };
In this case you don't need to explicitly disallow these for derived class, since the default implementation will have to use the parent's implementation first. So if you don't try to access these in your code:
int main() {
A a;
}
it will be perfectly valid. However if you try to copy:
int main() {
A a;
A a2 = A(a);
}
compiler will complain about class A trying to access private members of B (however semantically the second scenario shouldn't happen).
One question about protected constructor. I learnt that the protected constructor can be used in the derived class. How ever, I found the code below has an error. Why does it happen like this?
class A
{
protected:
A(){}
};
class B: public A {
public:
B() {
A* f=new A(); // Why it is not working here
}
};
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).
When a base class has a protected constructor, you can't instantiate the class directly. But you can do this to call the constructor from the base class constructor:
class A {
protected:
A() {}
};
class B: public A {
public:
B() : A() // allowed to access constructor like this
{
A* f = new A(); // Not allowed to access constructor like this!
}
};
A direct call to the constructor as shown below gives you the following error with gcc version 4.1.2:
A* f = new A(); // Not allowed to access constructor like this!
test.cpp:4: error: A::A() is protected
However, you this call to the constructor gives no errors:
B() : A() // allowed to access constructor like this
The reason behind this is that the second call accesses the A() constructor through inheritance, which is allowed. However, this tries to explicitly create a new instance of A() by calling the constructor directly:
A* f = new A(); // Not allowed to access constructor like this!
This might seem unintuitive, as B should be able to access A's constructor because B inherits from A. However, if you declare a constructor protected in C++, you can't create an instance of that class except through inheritance or a friend relationship.
Let me put my answer in steps:
1) Constructors don't get Inherited and that why in derived class, they can't be over ridden.
2) Constructors are invoked and not called.
3) If you have declared a simple function in A say protected void print() and then tried calling it in B, It would have worked. This happens bcoz, B has inherited this function.
4) When you do something like this b : a(), you are invoking the constructor and that's allowed.
5) Try making B a friend class of A and then run and see if it works.
Hope this helps.
I had the same question as this, and this link make me clear.
cppreference says like this:
Protected members form the interface for the derived classes (which is
distinct from the public interface of the class).
A protected member of a class Base can only be accessed
1) by the members and friends of Base
2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)