【问题标题】:Can I cast a derived class to a private base class, using C-style cast?我可以使用 C 风格的转换将派生类转换为私有基类吗?
【发布时间】:2013-07-29 07:22:20
【问题描述】:

我可以这样做吗?

class A { ... };

class B : private A
{
    const A &foo() const
    {
        return *((const A *)this);
    }
};

我可以采用从基类私有继承的子类并将其转换为基类的公共版本吗?如果没有虚拟方法,我可以这样做吗?

我的猜测是肯定的,但我想确保它是安全/便携的。

【问题讨论】:

  • 我不确定我会说这是可能的,尽管这有点违背私有继承的目的......
  • 按照“私有”继承的含义,我会说这不是一件好事。这种继承意味着“是根据”实现的,而公共继承是一种“is-a”关系。
  • 为什么我想要这个可怕的 hack:关键是从存储配置的键/值字典继承,通常将此字典隐藏在友好的方法后面以获取/设置各种配置项,但随后能够快速返回字典本身。返回一个副本是可以的,但我想知道我是否可以返回 const 'this'。显然没有必要,但从代码清洁度和惯用代码 POV 来看并非毫无意义。
  • 这是合法的,你不需要 C 风格的演员表。事实上,可以在外部使用 C 样式转换来打破 private 关系:B b; A& ar = *(A*)&b; 即使在 B 类之外也很乐意编译(即访问说明符被 C 样式转换忽略)
  • 你为什么要这样做? -- 我见过类似的东西用于将接口与实现分开。在您的类型提供 X 的接口上,实现是通过在需要您扩展类型 T 的特定 API 中注册来完成的。从T 继承不是您的接口,是您特定实现的要求,如果您更改提供程序,则可以删除该继承而不影响用户代码。

标签: c++ casting upcasting private-inheritance


【解决方案1】:

是的,您可以:标准 §5.4/7:

... 下面的 static_cast 和 reinterpret_cast 操作 (可选地后跟一个 const_cast 操作)可以使用 显式类型转换的强制转换表示法,即使基类 类型不可访问:

指向派生类类型对象或派生左值的指针 类类型可以显式转换为指针或引用 分别明确的基类类型;

尽量不要,因为它违背了私有继承的目的。

【讨论】:

  • 从事 C++ 已经快十年了,我仍然发现了这种语言的一些角落。不确定这是对语言的好评论还是坏评论。应该是坏的吧。但是,嘿,为什么现在停下来。 :)
  • 确实它有许多棘手的角落:裸指针、new 与 new[]、悬空引用、非虚拟析构函数、std::auto_ptr(尽管谢天谢地已被弃用)等等。我什至很想将模板添加到列表中,但这会冒着被否决/普遍嘲笑的风险!
  • 但是模板非常有趣!实际上,它们是我最喜欢的语言部分,尽管绝对属于瑞士军队火箭筒类别,并且不要过度使用
  • 如何将“模板”和“过度使用”这两个词放在同一个句子中?哦,等等,你没有。但他们还是靠得太近了。
  • 建议编辑答案以明确声明这是static_cast-like 操作而不是reinterpret_cast
【解决方案2】:

是的,这是明确允许的。 Alexandrescu 在Modern C++ Design 中广泛使用了这一点,用于他的基于策略的设计方法:

template <typename Policy>
class foo : Policy
{
    public:
        void do_something()
        {
            Policy & p = *this;
            p.do_something();
        }
};

因此,虽然用例可能有限,但还是有一些。

【讨论】:

  • 但这不是 c 风格的演员表吗?它只是从类内部隐式转换为私有基数。我错过了什么吗?
  • 隐式转换比 c 风格转换更受限制。
  • 您答案中的代码示例没有任何 C 风格的强制转换,也没有任何基类 Policy 无法访问的代码。所以它似乎与 OP 所询问的任何事情都无关。
【解决方案3】:

根据您的问题标题,答案取决于。但是对于您的源代码中的情况,答案是肯定的。

有两个因素会影响答案:

  1. 如果您使用 C 样式转换,则可以,因为如果没有可用的转换,转换将调用重新解释转换。您可以将任何类型的指针转​​换为目标类型的指针。但是如果有 MI,那么大多数 C++ 语言实现的结果可能是不正确的。

  2. 如果您在成员函数内部进行强制转换(没有 C 风格的强制转换),答案将是肯定的,因为在成员函数内部可以访问基类。如果表达式位于基类无法访问的位置,则会出现编译错误。

C++ 标准中有更多关于标准转换的细节

A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class (Clause 10) of D. 
If B is an inaccessible (Clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. 
The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type.

编辑 2:让答案更详细。

【讨论】:

  • 你引用的那段是关于隐式类型转换的。它指出,如果基类不可访问,则不能将派生类指针转换为它。在派生类内部,基类是可访问的,所以这不适用。此外,对于 C 风格的演员表还有一个特殊规则,请参阅 Bathshebaanswer
  • "如果你使用 C 风格的转换,它会是的,因为如果没有可用的转换,转换会调用 re-interpert cast。"不,在这种情况下,C 风格的转换将通过引用的特殊规则 Bathsheba 与 static_cast 执行类似的操作(即忽略基类不可访问)。顺便说一句,您应该使用&gt; 或引号按钮来插入引号,而不是四个空格或代码按钮。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-08
  • 2013-11-17
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
相关资源
最近更新 更多