为什么C风格的转换允许你转换为私有基类?

10

假设我们有以下代码:

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_cast、dynamic_cast 和 reinterpret_cast 正确表达。但是为什么一开始就允许这样做呢?这难道不会破坏封装性吗?

更新 这不是链接问题的重复,因为这个问题涉及到 C++ 的设计决策。它并不是询问我能否用该语言做什么或不能做什么,而是询问为什么可能做出某些决策。


5
因为 C 风格的强制类型转换太过强大,不应使用。 - Cat Plus Plus
1
因为 C 语言中的它们是最糟糕的部分之一。 - Cat Plus Plus
将此问题链接到一个具有高质量答案的问题。 - M.M
@M.M来吧,链接的问题是“是否可以使用C风格的转换”,我的问题是关于设计和演变以及为什么允许这样做的决定。 - unkulunkulu
@unkulunkulu,这里没有一个答案解释了为什么(而且被接受的答案是错的),而在链接的问题中,有一个具有有效用例的答案。 - M.M
显示剩余6条评论
3个回答

8
当使用C风格的指针转换将基类和派生类之间的指针进行转换时,它的行为类似于static_cast - 即使基类是私有的也是如此。
(无关指针类型之间的C风格转换属于reinterpret_cast。)
标准规定:
引用来自:

通过下列方式执行的转换:

— 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时即使基类不可访问,转换也是有效的

— 派生类类型的对象的指针或派生类类型的lvalue或rvalue分别可以显式转换为单一基类类型的指针或引用;

— 派生类类型的成员指针可以显式转换为非虚基类类型的非歧义性成员指针;

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

您的情况在第一点中描述,因此通过static_cast进行转换并调整指针。

请注意,不允许将reinterpret_cast用于私有基类。 - K-ballo
reinterpret_cast 有其限制。 - Cat Plus Plus
@Seth Carnegie 是的。你只能使用C风格的转换来实现这个。请参考https://dev59.com/IXRC5IYBdhLWcg3wVvct#332086。 - user1203803
@SethCarnegie,但是我想问的是为什么,我知道这是标准,我只是想感受一下动机。我仍然认为我的答案包含可能的原因。但也许这个问题有点主观。 - unkulunkulu
1
我不是那个给你点踩的人。然而,这个回答基本上是在说“它并不像你想象中的那样工作”。但随后它又纠正自己,加上了“哦,它实际上确实是那样工作的……”。然后它继续基本上重复了我在问题中已经陈述过的内容。我在这里没有看到“为什么?”的答案。 - AnT stands with Russia
显示剩余17条评论

1

这是因为在 C 语言中,允许使用此转换将任何指针转换为任何其他指针,而 C++ 尽可能地与 C 兼容,但在处理类时尝试做出正确的工作,因此在这种情况下,C 风格的转换比 reinterpret_cast 更强。


这不是正确的行为。 - Cat Plus Plus
好的,我发帖后就意识到答案了,它是C语言的遗产,好的,我明白了:D - unkulunkulu
@CatPlusPlus,我的意思是它会适当地修改指针的值。 - unkulunkulu
Indeed: http://ideone.com/rvqdL5 - gx_
这个答案最多是误导性的 - 在这种情况下,C风格的转换与reinterpret_cast完全不同的。 - M.M

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

那么,在问题的示例中,你能推荐使用什么替代C风格转换? - unkulunkulu
你不应该将一个类型转换为它私有继承的类型。如果你想这样做,应该使用公有继承。 - robert
我理解这一点,因此提出了这个问题,它涉及到C++中的设计决策,而不是好的代码建议 :) 因此,我认为我的回答很到位。 - unkulunkulu
决策是这是“较小”的邪恶。问题在于,C样式的类型转换可以做许多事情,并且从调用的上下文中并不清楚。在这种特定情况下,如果该规则不在语言中,则会回退到比违反访问说明更糟糕的reinterpret_cast - David Rodríguez - dribeas
这个答案最多是误导性的 - 当两个指针类型通过继承相关时,C风格的转换会表现出不同的行为。 - M.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接