【问题标题】:Why does C style cast allow you to convert to a private base class? [duplicate]为什么 C 样式转换允许您转换为私有基类? [复制]
【发布时间】:2012-05-26 21:50:00
【问题描述】:

假设我们有这个代码

class A {
public:
    A() : x(1) {}
    virtual ~A() {}

    int x;
};

class B {
public:
    B() : y(2) {}
    virtual ~B() {}

    void g()
    {
        cout << "B::" << y << endl;
    }

    int y;
};

class C : private A, private B {
public:
    void f()
    {
        B* p = static_cast<B*>( this );
        p->g();
    }
};

int main()
{
    C c;
    ((B*)&c)->g();

    return 0;
}

主函数中的 C 风格转换不能正确地用 C++ 转换(static_castdynamic_castreinterpret_cast)表示。但是首先允许这样做的原因是什么?不伤害封装吗?

更新 这不是链接问题的重复,因为这个问题是关于 C++ 中的设计决策。它不问我能用这种语言做什么或不能做什么,它问为什么会做出某些决定。

【问题讨论】:

  • 因为 C 风格的转换太强大了,永远不应该使用,这就是原因。
  • @CatPlusPlus,这正是我的意思,为什么他们有这么大的权力?
  • @unkulunkulu 因为这是 C++。
  • 因为 C。它们是语言中最糟糕的部分。
  • 将此问题与高质量答案相关联。

标签: c++ class casting upcasting


【解决方案1】:

当在指向基类和派生类的指针之间使用 C 风格的指针转换时,它的行为类似于 static_cast - 即使基类是私有的。

(不相关指针类型之间的 C 样式转换为 reinterpret_casts)。

标准说:

执行的转换

——一个 const_cast (5.2.11),

——一个 static_cast (5.2.9),

——一个 static_cast 后跟一个 const_cast,

——一个 reinterpret_cast (5.2.10),或者

——一个 reinterpret_cast 后跟一个 const_cast,

可以使用显式类型转换的强制转换表示法来执行。相同的语义限制和行为适用,除了在以下情况下执行 static_cast 时即使基类不可访问,转换也是有效的

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

——指向派生类类型成员的指针可以显式转换为指向明确的非虚拟基类类型成员的指针;

——指向明确非虚拟基类类型对象的指针、明确非虚拟基类类型的glvalue或指向明确非虚拟基类类型成员的指针可以显式转换为分别是指向派生类类型成员的指针、引用或指针。

你的情况在第一点有描述,所以转换由static_cast完成并调整指针。

【讨论】:

  • 请注意,私有基类的reinterpret_cast 是不允许的。
  • reinterpret_cast 有限制。
  • @Seth Carnegie 是的。您只能使用 C 风格的强制转换来做到这一点。见stackoverflow.com/a/332086/1203803
  • @Radek'daknok'Slupik 是 C 风格的演员表,没有用其他 _cast 运算符描述?
  • 我不是反对者。然而,这个答案基本上是说“它不像你想象的那样工作”。但随后它通过添加“哦,它确实以这种方式工作......”来纠正自己。然后它继续基本上重复问题中已经说明的 id。我没有看到“为什么”的答案在这里提问。
【解决方案2】:

这是因为在 C 中允许使用这种强制转换将任何指针转换为任何其他指针,并且 C++ 尽可能地与 C 兼容,但在涉及到类时试图做好正确的工作,所以在这种情况下,C 风格的演员表比reinterpret_cast 强。

【讨论】:

  • 这不是正确的行为。
  • 好的,刚发完我就知道答案了,是C遗产,好的,我明白了:D
  • @CatPlusPlus,我的意思是它适当地修改了指针值
  • 这个答案充其量是误导 - 在这种情况下,C 风格的演员表完全不同reinterpret_cast
【解决方案3】:

C 风格的转换允许您将任何类型转换为任何其他类型。如果您愿意,可以使用(std::istream*)&amp;c,但不建议这样做。

【讨论】:

  • 那么你能推荐什么来代替问题示例中的 C 风格转换?
  • 您不应该能够将一种类型转换为它私有继承的类型。如果你想这样做,你应该使用公共继承。
  • 我明白,因此问题在于 C++ 中的设计决策,而不是好的代码建议 :) 所以我认为我的回答是中肯的。
  • @unkulunkulu:决定这是较小的邪恶。问题是 C 风格的转换可以做很多事情中的一件,并且从调用的上下文中不清楚。在这种特殊情况下,如果该规则不在语言中,它将退回到reinterpret_cast,这比破坏访问说明符更糟糕。
  • 这个答案充其量是误导 - 当两个指针类型通过继承相关时,C 风格的转换表现不同。
猜你喜欢
  • 2019-03-12
  • 1970-01-01
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 2010-11-30
  • 2017-08-12
  • 2021-10-09
  • 2011-04-26
相关资源
最近更新 更多