Implementation of protected / private inheritance in compiler - c++

If a class derives from another class like
class B{};
class D : private B{};
then I can not create derived class objects like:-
B* ptr = new D;
If I check the assembly difference of this code vs assembly code of class D deriving
from class B publically, I don't find any differnce.
Can anyone explain exactly how and at what stage the complier is differentiating between public / protected and private inheritance.

The compiler checks protection (public/private) in the frontend while parsing your code. Once it gets to the optimizer and code generation they are gone.

private means: "Can only be accessed from within the class or friends of the class"
Private inheritance is the same as public inheritance; but there are restrictions on which code that can access the fact that D is inherited from B. Since you can do all the same things with private inheritance as with public inheritance (but only in a limited scope), it makes sense that the two implemented in an identical way.
Your claim that you can't make derived classes with B* ptr = new D; is only true if you are not in the scope of D; for example, this works:
class B{};
class D : private B{
public:
void makeB() {
B* ptr = new D;
}
};

The compiler just parse the language and make sure that you do not break the rules.
It then goes on to produce some machine code (maybe via assembly language).
As long as you have not broke the rules of C++ it is free to do the implementation in machine code.
So at that stage private/public/protected or whatever does not matter. Higher up the chain you have been protected

The compiler checks the access, and gives a compilation error, if the base class is inaccessible. There is no need to emit different code to the executable.
There are cases where different code may be emitted (e.g. use of RTTI, dynamic_cast, etc which do runtime type checks) but you're not using that in this case.
Incidentally,
B* ptr = new D;
can be performed in a function that is a member or friend of D.

You are wrong. You certainly can create objects:
D* pd = new D;
You can't, however, cast a D object to the base B type, because of its 'private' scope.
You can see it, for example, with this code:
D d; // created successfully
B *pd = & d; // forbidden
B &pb = d; // forbidden
The messages are clear:
'type cast' : conversion from 'D *' to 'B *' exists, but is inaccessible
'type cast' : conversion from 'D *' to 'B &' exists, but is inaccessible
which means object D d exists and it can be seen as type B, it just can not be accessed in this context.
That's why you do not see any difference in assembly: operations which are allowed, look the same in both cases, what's different is that some operations are not allowed.

Related

"Crossing the hierarchy" -- why not?

We have a multiple inheritance hierarchy:
// A B
// \ /
// C
//
Both A and B are abstract classes. C is actually a templated class, so downcasting is near impossible if you have a B and you want to access a member of it as an A.
All A's and B's must be C's, since that is the only concrete class in the hierarchy. Therefore, all A's must be B's, and vice versa.
I'm trying to debug something quickly where I have a B that I need to access A::name of. I can't downcast to C because I don't know the templated type of it. So I'm writing code like below and surprisingly it doesn't work; and I'm wondering what gives.
struct A { virtual void go() = 0; std::string name; };
struct B { virtual void go() = 0; };
struct C : A, B { void go() override { } };
int main()
{
C c;
c.name = "Pointer wonders";
puts(c.name.c_str()); // Fine.
B* b = (B*)&c;
//puts(b->name.c_str()); // X no from compiler.
A* a1 = (A*)&c;
puts(a1->name.c_str()); // As expected this is absolutely fine
// "Cross" the hierarchy, because the B really must be a __C__, because of the purely virtual functions.
// neither A nor B can be instantiated, so every instance of A or B must really be a C.
A* a2 = (A*)b;
puts(a2->name.c_str()); // Why not??
// If you downcast first, it works
C* c2 = (C*)b;
A* a3 = (A*)c2;
puts(a3->name.c_str()); // fine
}
First of all, stop using C style cast. The compiler won't complain if you do something wrong (C style cast usually do not works in multiple inheritance).
Any cast that cause run-time error in you example would not compile with a static_cast. While it is a bit longer to type, you get instant feedback when used improperly instead of undefined behavior that will sometime corrupt data and cause problem long afterward when that data is use.
As A and B contains virtual function, you can easily use dynamic_cast without knowing C. If you know C, you could use static_cast to C if you know there is a derived C for sure. But why not use virtual functions and not do any crossing between siblings?
The reason it does not works is because C-style cast can do any of the following cast:
static_cast
reinterperet_cast
const_cast
Also, C style cast will do a reinterpret_cast if the definition of a class is missing. You also need to be very careful with void *as you must convert back to original type.
As a simplified rule, you can imagine that C cast is like doing either a single static_cast (known child or parent class or primitive types like int) or reinterpret_cast (unknown type, not a parent/child class) followed by a const_cast if necessary.
C * --> void * --> B * won't work with any C or C++ cast.
Th primary reason that such cast don't works is that the compiler must adjust this pointer when doing a cast and multiple inheritance is used. This is required to take into account that the A and B part start at a distinct offset.
Alternatively, you can add a virtual function A * GetA() = 0 in B and implemente it in C to have your own way to navigate. That can be an option if is unknown and RTTI must be disabled (for ex. on embedded systems).
Honestly, you should avoid multiple inheritance and casting as it make the code harder to maintain as it increase coupling between classes and it can cause hard to find bug particularily when mixing both together.

C++ Syntactical anomaly for instantiation of a derived class

I am working with a GitHub library and ran across a derived class instantiation that perplexes me. In abbreviated form,
class A
{
public:
A() {}
int AFunc(void) { return(1); }
};
class B : public A
{
public:
B(void) : A() {}
int BFunc(void) { return(2); }
};
Within an include file, the class is instantiated as follows:
A &tObject = *(new B());
Sample code then refers to 'tObject' as global variable calling methods from class A and/or B.
For example:
tObject.AFunc();
tObject.BFunc();
So here's the question, is that instantiation legal?
The compiler is only fussing on the call to a service class's method, saying that class A has no such member. That error makes sense to me and I've narrowed the issue to the above explanation.
While I do not have broad compiler experience, I have been programming in C++ for many years. I've never seen such a construct.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
In my experience, I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct. Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
An insight is highly appreciated.
It cannot. The compiler is right to complain, there is no way this is valid. Remember that C++ is a static language, which means that the compiler will try to find a function named BFunc in A, which it cannot, as there is no such function.
This might be a compiler extension of some sort, but anyways, this isn't legal standard C++. Most probably, the author wanted to make BFunc a virtual method in A, which would have made the access legal.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
As explained, this cannot be.
I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct.
You can also do this with references, not just with pointers. Although this is done less often than pointers, so this might explain why you haven't encountered this yet.
Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
Exactly, this is the correct way to access the derived class members. As then the compiler will know the type of the object and can actually find BFunc and call it. Now, if the type is not really a B, then you have undefined behavior, but yes, this is what one should do.
Also, please get your terminology right:
the class is instantiated as follows
If there are no templates involved, then there is no instantiation happening. The only thing you are doing here is declaring or more specifically defining a variable named tObject.
// The declaration of the reference as a reference to the base class is not a problem, and is actually performed in some STL implementations.
class A
{
};
class B : public A
{
public:
void f1() {}
};
int main()
{
A * a = new B; // You know its OK using pointers
A & a2 = *(new B); // Also OK, a2 is a reference for a place in memory which is-a-kind-of A
// a2.f1(); // Will not compile - compiler only knows for sure its of type A
((B&) a2).f1(); // This will work. There is really a B there
return 0;
}

Downcast in a diamond hierarchy

Why static_cast cannot downcast from a virtual base ?
struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};
int main()
{
D d;
A& a = d;
D* p = static_cast<D*>(&a); //error
}
g++ 4.5 says:
error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’
The solution is to use dynamic_cast ? but why. What is the rational ?
-- edit --
Very good answers below. No answers detail exactly how sub objects and vtables end up to be ordered though. The following article gives some good examples for gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting
The obvious answer is: because the standard says so. The
motivation behind this in the standard is that static_cast
should be close to trivial—at most, a simple addition or
subtraction of a constant to the pointer. Where s the downcast
to a virtual base would require more complicated code: perhaps
even with an additional entry in the vtable somewhere. (It
requires something more than constants, since the position of
D relative to A may change if there is further derivation.)
The conversion is obviously doable, since when you call
a virtual function on an A*, and the function is implemented
in D, the compiler must do it, but the additional overhead was
considered inappropriate for static_cast. (Presumably, the
only reason for using static_cast in such cases is
optimization, since dynamic_cast is normally the preferred
solution. So when static_cast is likely to be as expensive as
dynamic_cast anyway, why support it.)
Because if the object was actually of type E (derived from D), the location of A subobject relative to D subobject could be different than if the object is actually D.
It actually already happens if you consider instead casting from A to C. When you allocate C, it has to contain instance of A and it lives at some specific offset. But when you allocate D, the C subobject refers to the instance of A that came with B, so it's offset is different.

Why is it allowed to call derived class' private virtual method via pointer of base class?

# include <iostream>
using namespace std;
class A
{
public:
virtual void f()
{
cout << "A::f()" << endl;
}
};
class B:public A
{
private:
virtual void f()
{
cout << "B::f()" << endl;
}
};
int main()
{
A *ptr = new B;
ptr->f();
return 0;
}
This code works correctly and prints B::f(). I know how it works, but why is this code allowed?
Access control is performed at compile time, not runtime. There's no way in general for the call to f() to know the runtime type of the object pointed to by ptr, so there's no check on the derived class's access specifiers. That's why the call is permitted.
As for why class B is permitted to override using a private function at all - I'm not sure. Certainly B violates the interface implied by its inheritance from A, but in general the C++ language doesn't always enforce inheritance of interface, so the fact that it's Just Plain Wrong doesn't mean C++ will stop you.
So I'd guess that there's probably some use case for this class B - substitution still works with dynamic polymorphism, but statically B is not a substitute for A (e.g. there can be templates that call f, that would work with A as argument but not with B as argument). There may be situations where that's exactly what you want. Of course it could just be an unintended consequence of some other consideration.
This code is allowed because f is public in A's interface. A derived class cannot change the interface of a base class. (Overriding a virtual method isn't changing the interface, nor is hiding members of a base, though both can appear to do so.) If a derived class could change a base's interface, it would violate the "is a" relationship.
If the designers of A want to make f inaccessible, then it should be marked protected or private.
Your base class is defining the interface for all the inherited children. I do not see why it should prevent the mentioned access. You can try deriving a class down from 'B' and use the Base interface to call , which would result in an error.
Cheers!
In addition to Steve's answer:
B is publically derived from A. That implies Liskov substitutability
Overriding f to be private seems to violate that principle, but actually it does not necessarily - you can still use B as an A without the code getting in the way, so if the private implementation of f is still okay for B, no issues
You might want to use this pattern is B should be Liskov substitutable for A, but B is also the root of another hierachy that is not really related (in Liskov-substitutable fashion) to A, where f is no longer part of the public interface. In other words, a class C derived from B, used through a pointer-to-B, would hide f.
However, this is actually quite unlikely, and it would probably have been a better idea to derive B from A privately or protected
Function access control check happens in later stage of a c++ function call.
The order in high level would be like name lookup, template argument deduction(if any), overload resolution, then access control(public/protect/private) check.
But in your snippet, you were using a pointer to base class and function f() in base class is indeed public, that's as far as compiler can see at compiler time, so compiler will certain let your snippet pass.
A *ptr = new B;
ptr->f();
But all those above are happens at compile time so they are really static. While virtual function call often powered by vtable & vpointer are dynamic stuff which happens at runtime, so virtual function call is orthogonal to access control(virtual function call happens after access control),that's why the call to f() actually ended B::f() regardless is access control is private.
But if you try to use
B* ptr = new B;
ptr->f()
This will not pass despite the vpointer & vtable, compiler will not allow it to compile at compile time.
But if you try:
B* ptr = new B;
((static_cast<A*>(ptr))->f();
This would work just fine.
Pretty much like in Java, in C++ you can increase the visibility of methods but not decrease it.

Getting rid of error C2243

Is it possible to getting rid of error C2243?
class B {};
class D : protected B {};
D d;
B *p = &d; // conversion from 'D *' to 'B &' exists, but is inaccessible
I had this error in my app and at the end I've managed to compile it by making an explicit conversion:
D d;
B *p = (B*)&d;
I can't understand why by making class D inherited protected from B makes the implicit conversion inaccessible.
I tried to avoid explicit conversion by creating a operator B() in class D in order to make the conversion accessible:
class B {};
class D : protected B
{
public:
operator B() {return *this;}
};
But there is no way.
Any other solution to avoid explicit conversion?
If you want to allow conversion, you should be using public inheritance.
Using protected or private inheritance, you are declaring that the fact that the derived type inherits from the base class is a detail that should not be visible from the outside: that's why you are getting that error.
You should regard non-public inheritance only as a form of composition with the added possibility to override methods.
Because protected and private inheritance are not is-a relationship, they are just syntax sugar for composition. Your classes can be rewritten exactly like this, but you lose the convenience of letting the compiler define b for you, and using b members directly instead of referring to it explicitly :
class D
{
protected:
B b;
};
For the second point of your question:
operator B() {return *this;}
This line has to do with B and D. D* and B* are totally different from B and D though they are pointers to them! to cast pointers, you could reinterpret the pointer:
B *p = reinterpret_cast<B*>(&d); // TOTALLY WRONG, although it compiles :)
Don't do the above line! I think you might give us more info of what you are trying to achieve.
Because out of D and Ds children, nobody knows that they are parent-child, so you need to do it explicitly.
Thats what protected inheritance means, only your family(children) will know that you inherit. And you could use it, for example in a children method, there an implicit conversion would be legal.
If you want to have implicit conversion out of your children you need to make it public for everyone to know.
The problem here is that you are trying to do an end run around the information hiding that the protected attribute provides. If you want to access an instance of D as a B, why have you inherited it as protected rather than public?. What you are saying in using protected inheritance is that you wish only instances of D and its descendants to be aware of the B component. You need to look again at what you want to accomplish.
The old C style cast that you are using has none of the subtlety of the newer C++ casts so it gives you code that will compile but the problem is really in the inheritance.
Did you try making operator B() public in class D? In the code you showed, it would be marked protected and still inaccessible. But I would avoid conversion operators in general if possible.
Still, inheriting protected B means you intend to prevent doing B* p = &d. Imagine if B was actually a protected member variable at the top of D. Just like you can't access D.b in that case, you can't access d as a B*, unless you cast it away.
So either inherit B publically, or use your casts. I'd go with inheriting B publically, because inheriting it protected basically says "Don't use me as a B", which you are trying to do anyway.
Because nobody outside knows they are parent-child,you only can perform this action in D's derived class.This is an example(Test in Visual Studio 2013):
class BASE{};
class BASE1 :protected BASE{};
class BASE2 :protected BASE1
{
public:
void func(BASE &a, BASE1 &b){a = b;}
};
void main()
{
BASE a;
BASE1 b;
BASE2 c;
c.func(a, b);;
system("pause");
}