Unlike other examples of this error message i already have a pointer to A
and want to retrieve the actual child class.
This kind of arrangement is part of some C++ wrapped C code there A
is some POD C structure (whatswhy no dynamic cast) and test
is some callback in C that calls C++ functionality and to retrieve the correct object the cast should be used.
But to prevent C++ user code messing the C-Baseclass i would like to have the inheritance protected
.
MSVC does not complain about this but g++ does!? Which one is correct from the standards point of view and why?
#include <iostream>
using namespace std;
// plain C structure
struct A{
int i;
};
// some C++ Wrapper class
struct B: protected A{
A* get() { return this; }
void print(){cout << i << endl;}
};
extern "C" {
// C callback that gives it this pointer
void test(A* io_self){
auto b2 = static_cast<B*>(io_self);
b2->print();
}
}
int main()
{
B b;
test(b.get());
return 0;
}
gives:
$g++ -std=c++11 -o main *.cpp
main.cpp: In function ‘void test(A*)’:
main.cpp:21:43: error: ‘A’ is an inaccessible base of ‘B’
auto b2 = static_cast<B*>(io_self);
^
From c++11 N3337 draft (a bit old but it's the one I have lying around) 5.2.9/11 (static_cast):
A prvalue of type “pointer to cv1 B,” where B is a class type, can be converted to a prvalue of type “pointer to cv2 D,” where D is a class derived (Clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D.
In this case, since you use protected
inheritance there is no valid standard conversion from B
to A
so your static_cast
is illegal (g++ is correct to diagnose it).
In this case since you're providing a c++ wrapper around a C API I think the simplest approach is to just stick with public inheritance and have a small amount of trust that your users won't abuse the C API directly if they've already consciously chosen to use your C++ API
If you use protected
inheritance, only derived types can be aware of that inheritance. As far as test
is concerned, there is no relation between A
and B
. Since a static_cast
can't cast pointers between unrelated types, you would need to reinterpret_cast
instead. Or you may be able to provide B
with a static method to preform this conversion, since B
is aware of the inheritance. For example :
// some C++ Wrapper class
struct B : protected A {
A* get() { return this; }
void print() { cout << i << endl; }
static B* cast_to_b(A* io_self) { return static_cast<B*>(io_self); }
};
extern "C" {
// C callback that gives it this pointer
void test(A* io_self) {
auto b2 = B::cast_to_b(io_self);
b2->print();
}
}
Be sure that the object referred to by A* io_self
is actually a B
and not just a A
or it's undefined behavior.
Are you sure protected
is the right inheritance for you here? It seems like private
inheritance might be clearer as there doesn't seem to be any intention of inheriting from B
. You may also want to consider forgetting about inheritance and simply giving B
a A
member.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With