是否有可能摆脱error C2243?
class B {};
class D : protected B {};
D d;
B *p = &d; // conversion from 'D *' to 'B &' exists, but is inaccessible
我在我的应用中遇到此错误,最后我设法通过显式转换来编译它:
D d;
B *p = (B*)&d;
我无法理解为什么通过使D类继承受B保护而使得隐式转换不可访问。
我尝试通过在D类中创建运算符B()来避免显式转换,以便可以进行转换:
class B {};
class D : protected B
{
public:
operator B() {return *this;}
};
但是没有办法。
避免显式转换的其他任何解决方案?
答案 0 :(得分:17)
如果要允许转换,则应使用公共继承。
使用受保护或私有继承,您声明派生类型从基类继承的事实是一个不应该从外部可见的细节:这就是您收到该错误的原因。
您应该将非公共继承仅视为一种组合形式,并且可以覆盖方法。
答案 1 :(得分:8)
由于protected
和private
继承不是is-a
关系,因此它们只是合成的语法糖。你的类可以像这样重写,但你不能让编译器为你定义b
,并直接使用b成员而不是明确地引用它:
class D
{
protected:
B b;
};
关于你问题的第二点:
operator B() {return *this;}
此行与B
和D
有关。 D *和B *与B和D完全不同,尽管它们是指向它们的指针!要转换指针,你可以重新解释指针:
B *p = reinterpret_cast<B*>(&d); // TOTALLY WRONG, although it compiles :)
不要做上述行!我想你可能会告诉我们你想要达到的目标的更多信息。
答案 2 :(得分:2)
因为D和Ds的孩子,没有人知道他们是亲子,所以你需要明确地做。
这就是保护继承意味着什么,只有你的家人(孩子)知道你继承了。你可以使用它,例如在子方法中,隐式转换是合法的。
如果你想让你的孩子隐性转换,你需要公开让所有人知道。
答案 3 :(得分:2)
这里的问题是您正试图绕过受保护的属性提供的隐藏信息。如果要将D的实例作为B访问,为什么要将其作为受保护而不是公共继承?您在使用受保护的继承时所说的是您只希望D及其后代的实例知道B组件。您需要再次查看要完成的任务。
您正在使用的旧C样式转换没有新的C ++转换的精妙之处,因此它为您提供了将编译的代码,但问题实际上在继承中。
答案 4 :(得分:0)
您是否尝试在D类中公开运算符B()?在您显示的代码中,它将被标记为受保护且仍然无法访问。但是如果可能的话,我会尽量避免使用转换运算符。
但是,继承受保护的B意味着您打算阻止做B * p =&amp; d。想象一下,如果B实际上是D顶部的受保护成员变量。就像你在这种情况下无法访问D.b一样,你不能将d作为B *访问,除非你把它丢弃。
所以要么公开地继承B,要么使用你的演员表。我继续公开继承B,因为继承它保护基本上说“不要用我作为B”,无论如何你都试图做。
答案 5 :(得分:0)
因为外面没有人知道他们是亲子,所以你只能在D的派生类中执行这个动作。这是一个例子(在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");
}