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)
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)
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)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++: overriding public\private inheritance
class base {
public:
virtual void doSomething() = 0;
};
class derived : public base {
private: // <-- Note this is private
virtual void doSomething()
{ cout << "Derived fn" << endl; }
};
Now if I do the following:
base *b = new derived;
b->doSomething(); // Calls the derived class function even though that is private
Question:
It's able to call the derived class function even though it is private. How is this possible?
Now if I change the inheritance access specifier from public to protected/private, I get a compilation error:
'type cast' : conversion from 'derived *' to 'base *' exists, but is inaccessible
Note: I am aware of the concepts of the inheritance access specifiers. So in the second case as it's derived private/protected, it's inaccessible. But I wonder about the answer to first question. Any input will be highly appreciated.
Access control is implemented at compile time, not run-time, while polymorphism (including the use of virtual functions) is a run-time feature.
In the first case the access check is done (as it is always done) on the static type that the call is made through. The static type of *b is base, and in that case doSomething() is public.
C++03 11.6 "Access to virtual functions" says:
The access rules (clause 11) for a virtual function are determined by
its declaration and are not affected by the rules for a function that
later overrides it. [Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); //OK:B::f()is public,
// D::f() is invoked
pd->f(); //error:D::f()is private
}
—end example]
Access is checked at the call point using the type of the expression used to denote the object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.
Keep in mind especially that "the access of the member function in the class in which it was defined (D in the example above) is in general not known". In general, at the point in your example where b->doSomething(); is called, the compiler may have no knowledge at all about derived (or child), much less whether or not the access to derived::doSomething() is private.
Private functions are meant to be hidden from the outside world and from the derived classes. Although you are overriding the access specifier of the parent's DoSomething and making it private, you are instantiating a base class; so in the first case, you can call base's DoSomething as it is public. This scenario can be used if you want to stop people deriving from your derived class.
In the second case, the private access specifier causes the base's members not to be exposed to the users of the derived class, which effectively makes the derived class useless.
The following simple example will produce a compiler error, since I accidently use private inheritance:
main.cpp:21: error: ‘A’ is an inaccessible base of ‘B’
class A
{
};
class B : /*ups forgot that -> public*/ A
{
};
int main(int , char *[])
{
A* test = new B;
return 0;
}
Could you help me and explain what exactly is inaccessible in the base class and why it is needed in the conversion from B* to A*?
Private inheritance means that for everyone except B (and B's friends), B is not derived from A.
Could you help me and explain what exactly is inaccessible in the base class and why it is needed in the conversion from B* to A*?
Ouside of B and the friends of B, the simple fact that B is an A is not visible. This is not hiding a member variable or member function, but hiding the relationship itself. That is why from main you cannot bind the result of new B with a pointer to A, because as far as main is concerned, B is not an A (in the same way that you could not do A * p = new unrelated;)
As to why it is needed, the answer it exactly the same: because without access to the relationship, the compiler does not know (well, it knows, but will not tell you) how to obtain a pointer to the A subject inside B, because as far as it can see within that context there is no relationship between A and B at all.
The conversion from B* to A* is inaccessible, because the base-class subobject is private. When you convert B* to A*, you return the pointer to the base-class subobject. The latter must be accessible for the conversion to be accessible. In any function that is friend to B the conversion becomes accessible. By the way, you can always access the conversion by an explicit cast.
A* p = (A*)(new B);
Note that in some cases just accessible conversion is required, but in some cases it is required that A be a public (stronger than accessible) base of B. For example, when you try to catch an exception of type B with catch(A&) - it is required that A be a public base class of B.
Since the reference or pointer of Base class can not point to object of inherited class, does it mean that protected and private inheritance is nothing to do with polymorphism?
Since B is inherited from A, the default constructor of A would be called before the constructor of B. But because it is private and not inherited to B, you get a compiler error.
Public/private inheritance is equivalent to public/private member variable.
The result of the conversion is a reference to the base class subobject of the derived class object.
I think the accessibility means the accessibility of the base class subobject of the derived class object.For client,only if we ues public inheritance,the base class subobject is accessible.For the member function of derived class,no matter we use public/protected/privaye inheritance, the base class subobject is accessible.
class A{
};
class B: private A{
private:
int* m_pb;
public:
B(){m_pb=new int(10)};
void func()
{
A* pa= new B; //OK
int *pmb = m_pb; //OK
}
};
int main()
{
B* pb = new B;
A* pa= pb; // inaccessible
int *pmb = pb->m_pb; // inaccessible
}
OK.I means that public/private inheritance is equivalent to public/private member variable.
reference:
http://pic.dhe.ibm.com/infocenter/ratdevz/v8r5/index.jsp?topic=%2Fcom.ibm.tpf.toolkit.compilers.doc%2Fref%2Flangref_os390%2Fcbclr21011.htm
I have a class with protected constructor:
class B {
protected:
B(){};
};
Now I derive from it and define two static functions and I manage to actually create objects of the class B, but not on the heap:
class A : public B {
public:
static B createOnStack() {return B();}
//static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};
B b = A::createOnStack(); //This works on VS2010!
The question is: 1) Is VS2010 wrong in allowing the first case? 2) Is it possible to create objects of B without modifying B in any way (no friendship and no extra functions).
I am asking, because it is possible to make something similar when dealing with instances of B and its member functions, see:
http://accu.org/index.php/journals/296
Thank you in advance for any suggestion!
Kind regards
Yes, this code is non-compliant. This is related to special rules for protected member access (C++03 draft, 11.5/1):
When a friend or a member function of a derived class references a protected nonstatic member function or
protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.10). Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5).
When you use B() or new B(), you're effectively using the constructor through a pointer to the base class.
You can create an object of type A (I assume that A is as posted - no additional members/non-static functions) and use it instead. If you're creating it on stack, everything should work fine, unless you're trying to assign other objects of type B to it. If you're creating it on heap, everything is fine as long as B's destructor is virtual. If B's destructor is not virtual, and you're returning new A() as a B*, then deleting the pointer is technically undefined behavior (5.3.5/3:
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
However you'll probably find it working fine in practice, so you can rely on the actual behavior if there is no other workaround (i.e. use it as a last resort).
There is a common misunderstanding on what protected actually means. It means that the derived class can access that particular member on itself not on other objects. The compiler should have rejected both functions as in both cases it is accessing the constructor of an object that is not of the derived type.
Another example, easier to discuss for its correctness would be:
struct base {
protected:
int x;
};
struct derived : base{
static void modify( base& b ) {
b.x = 5; // error
}
};
The commented line is an error as it is trying to modify an object of type base, not necessarily a derived object. If the language allowed that code to compile, then you would be able to modify an object of type base or even objects of types derived1, derived2... effectively breaking access rules.
struct derived2 : base {};
int main() {
base b;
derived2 d;
derived::modify( b ); // modifying a base!!!
derived::modify( d ); // modifying a derived2!!!
}