【问题标题】:Why reinterpret_cast does work in private inhertiance为什么 reinterpret_cast 在私有继承中起作用
【发布时间】:2018-12-11 14:45:36
【问题描述】:

我在应用继承时正在阅读有关访问说明符的信息,并且我知道在 private inheritance 中,我们无法使用指针/引用从派生类转换为基类。

但是当我使用reinterpret_cast 时,它起作用了。下面是我的测试代码:

class base {
int _a;
public: 
    base(int a): _a(a) {}
    base(): _a(0) {}
};

class derived : private base
{
public:
    derived(int b):base(b) {};  
};

int main() {

    derived b(25); 
    base &a = static_cast<base&>(b);//this line will generate a compile error
    base &c = reinterpret_cast<base&>(b);  //here it works 
}

所以我的问题甚至是私有继承,为什么基类会使用retinterpret_cast 公开?

谢谢!

//EDIT 2

class base {
    int _a; 
public:         
    base(int a): _a(a) {}
    base(): _a(100) {}  
    ~base() { std::cout << "deleting base" << _a << "\n"; }
};

class derived : private base
{
public:
    virtual ~derived() = default;
    derived(int b):base(b) {};
};

int main() {

    derived b(25); 
    base &c = reinterpret_cast<base&>(b); 
}

//OutPut : Deleting 25

【问题讨论】:

  • 您不应该使用static_castreinterpret_cast 进行向上转换或向下转换。请改用dynamic_cast
  • 是的,你是对的,我必须使用需要多态类的dynamic_cst,但它是用于测试:)
  • reinterpret_cast 与旧的 C 风格转换非常相似,因为它基本上告诉编译器“我知道我在做什么,不要打扰我”。如果您实际上不知道自己在做什么,或者犯了任何错误,编译器仍然不会打扰您,并且会很乐意借给您一把枪,这样您就可以朝自己的脚开枪了。
  • 在实践中和简单的继承情况下,static_cast、C 风格的强制转换、reinterpret_cast 都被编译为无操作(即不生成代码,如标识函数) .但是,dynamic_cast 有运行时成本(并且需要一些生成的代码)
  • “所以我的问题甚至是私有继承,为什么基类会使用 retinterpret_cast 公开” - 不是。即使derived 没有从base 继承根本reinterpret_cast 仍然可以编译。

标签: c++ casting reinterpret-cast


【解决方案1】:

是否违反了私有继承?不是真的。

C++ 中的可访问性仅影响标识符可用于以有效方式引用某事物的范围。该系统旨在防止墨菲,而不是像您使用的马基雅维利技巧。

reinterpret_cast 基本上是在告诉编译器“忘记你所知道的,相信我的判断吧”。确实如此。你声称这个左值实际上是指base?好吧,随你便吧。但是编译器不会做任何事情来保护你,它假设你知道你在做什么。它很容易断裂。有@Dani 的例子,还有这个:

class derived : private base
{
public:
    virtual ~derived() = default;
    derived(int b):base(b) {};  
};

如果您尝试使用c 并调用使用_a 的成员函数,您认为会发生什么?它会找到什么?

【讨论】:

  • C 类公开地从 A 和 B 派生(但如果我理解了这个例子,那些后者私下从基础驱动)所以 C 不能调用 _a。如果我错了,请纠正我。
  • @Blood-HaZaRd - 什么类C?您示例中的 c 是对基础的引用。
  • @Blood-HaZaRd - 您的编辑不使用引用 c 来访问对象...您看到的输出来自常规程序流,当 derived 对象被销毁时,基类构造函数也被调用。很抱歉,但此时我认为您需要获取 back to basics
  • @Blood-HaZaRd - 差不多。生活(和 C++)当然更复杂。有时可以使reinterpret_cast 工作。关键是当您reinterpret_cast 时,它会告诉编译器您确切知道发生了什么。所以最好小心。
  • @Blood-HaZaRd - 是的,这是需要更深入知识的地方之一。静态转换要求编译器正确调整指针,然后 reinterpret_cast 获取返回的指针并从中取出一个整数。结果是高度定义的实现。
【解决方案2】:

reinterpret_caststatic_cast不一样
考虑以下示例:

class A { int a; }
class B { int b; }
class C : public A, B { }

使用 static_cast 将 C 转换为 B 会将指针更改为正确的结果,而 reinterpret_cast 将保持指针不变,这是不正确的。

【讨论】:

  • static_castC 的范围之外无法工作。
  • 如果您断言某事是真实的,这一点很重要。 “使用 static_cast 将 C 转换为 B 会更改指向正确结果的指针” - 不在C 的范围之外。这很重要,因为将来有人可能会尝试它,但它不会编译。 static_cast 尊重访问修饰符。顺便说一句,B 仍然是私人的。
  • 我并不是想说你的整个论点都是错误的,MI 确实是一个例子,说明它可能会严重失败。
  • @Dani:我的目标是知道为什么当我使用 reinterpret_cast 私有继承时它可以检索到基类的引用?抱歉,如果我没有在您的回答中看到线索。
  • @Blood-HaZaRd:这是未定义的行为,在常见的编译器中它在某些条件下工作。在我的示例中的多重继承中,它不起作用。在您的情况下,它可能有效,因为基类在类中占据偏移量 0。
猜你喜欢
  • 1970-01-01
  • 2022-01-04
  • 2013-10-23
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
  • 2015-02-12
  • 2014-09-09
  • 1970-01-01
相关资源
最近更新 更多