与此错误消息的其他示例不同,我已经有一个指向A
并且想要检索实际子类的指针。
这种安排是一些C ++包装的C代码的一部分A
是一些POD C结构(whatswhy没有动态转换)和test
是C中的一些回调,它调用C ++功能并检索应该使用演员表的正确对象。
但是为了防止C ++用户代码弄乱C-Baseclass,我想拥有继承protected
。
MSVC不会抱怨这个,但g ++会这样做!? 从标准的角度来看哪一个是正确的?为什么?
#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;
}
给出:
$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);
^
答案 0 :(得分:4)
如果使用protected
继承,则只有派生类型才能知道该继承。就test
而言,A
和B
之间没有关系。由于static_cast
无法在不相关的类型之间转换指针,因此您需要reinterpret_cast
。或者,您可以为B
提供静态方法来执行此转换,因为B
知道继承。例如:
// 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();
}
}
确保A* io_self
引用的对象实际上是B
,而不仅仅是A
或未定义的行为。
你确定protected
对你来说是正确的继承吗?似乎private
继承似乎更清晰,因为似乎没有任何继承B
的意图。您可能还想考虑忘记继承并简单地给B
A
成员。
答案 1 :(得分:3)
来自c ++ 11 N3337草案(有点旧,但它是我躺在那里的)5.2.9 / 11(static_cast):
类型为“指向cv1 B的指针”的prvalue,其中B是类类型,可以是 转换为“指向cv2 D的指针”的prvalue,其中D是一个类 如果是有效的标准转换,则从B派生(第10条) “指向D的指针”到“指向B的指针”存在(4.10),cv2是相同的 cv-qualification为,或者比cv1更高的cv资格,而B是 既不是D的虚基类,也不是虚基的基类 D级。
在这种情况下,由于您使用protected
继承,因此B
到A
之间没有有效的标准转换,因此您的static_cast
是非法的(g ++对于诊断是正确的) )。
在这种情况下,由于您提供了围绕C API的c ++包装器,我认为最简单的方法是坚持使用公共继承,并且对用户不会直接滥用C API具有少量信任如果他们已经有意识地选择使用您的C ++ API