10

是否有可能摆脱错误 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;

我不明白为什么通过从 B 继承受保护的类 D 会使隐式转换无法访问。

我试图通过在 D 类中创建运算符 B() 来避免显式转换,以使转换可访问:

class B {};
class D : protected B 
{
 public:
 operator B() {return *this;}
};

但是没有办法。

还有其他避免显式转换的解决方案吗?

4

6 回答 6

18

如果你想允许转换,你应该使用公共继承。

使用受保护或私有继承,您声明派生类型从基类继承的事实是一个从外部不可见的细节:这就是您收到该错误的原因。

您应该仅将非公共继承视为一种组合形式,并增加了覆盖方法的可能性。

于 2009-09-24T13:51:05.273 回答
8

因为protectedprivate继承不是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 :)

不要做上面的行!我认为您可能会向我们提供有关您要实现的目标的更多信息。

于 2009-09-24T13:49:21.343 回答
2

因为在 D 和 Ds 孩子中,没有人知道他们是父子,所以你需要明确地做。

这就是受保护的继承意味着,只有你的家人(孩子)会知道你继承。您可以使用它,例如在子方法中,隐式转换是合法的。

如果您想从您的孩子身上进行隐式转换,您需要将其公开让所有人都知道。

于 2009-09-24T13:51:06.177 回答
2

这里的问题是您正试图围绕受保护属性提供的信息隐藏进行最终运行。如果您想以 B 的身份访问 D 的实例,为什么要将它作为受保护而不是公共继承?您在使用受保护继承时所说的是,您只希望 D 及其后代的实例知道 B 组件。你需要重新审视你想要完成的事情。

您正在使用的旧 C 样式转换没有新 C++ 转换的微妙之处,因此它为您提供了可以编译的代码,但问题实际上出在继承上。

于 2009-09-24T14:07:46.173 回答
0

您是否尝试将运算符 B() 在 D 类中公开?在您显示的代码中,它将被标记为受保护并且仍然无法访问。但如果可能的话,我一般会避免转换运算符。

尽管如此,继承受保护的 B 意味着您打算阻止 B* p = &d。想象一下,如果 B 实际上是 D 顶部的受保护成员变量。就像在这种情况下您无法访问 Db 一样,您无法将 d 作为 B* 访问,除非您将其丢弃。

所以要么公开继承 B,要么使用你的演员表。我会公开继承 B,因为继承它受保护基本上说“不要将我用作 B”,无论如何你都在尝试这样做。

于 2009-09-24T13:54:24.203 回答
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");
 }
于 2014-11-24T10:34:40.970 回答