【问题标题】:Need some assist to understand class inheritance (C++)需要一些帮助来理解类继承(C++)
【发布时间】:2019-04-06 22:22:36
【问题描述】:

我正在尝试为自己的目的扩展其他人的 API,并且我正在尝试在这种情况下了解类继承。

我已经编写了这个最小的程序:

#包括 类first_class { 上市: first_class() {}; }; 第二类:第一类{ 私人的: 整数y; 上市: int get_y() { 返回 y; } 第二类(){ y=99; } }; int main() { first_class* a = new first_class(); second_class* b = 新的 second_class(); int q = ((second_class*)a)->get_y(); printf("%d\n",q); int r = b->get_y(); printf("%d\n",r); }

first_class 什么都不做,也没有成员。 second_class 继承自 first_class,但增加了一个私有成员 y 和一个 getter 函数 get_y();

当我在 second_class 的实例上调用 get_y() 时,它按预期工作。当我对已转换为 second_class 的 first_class 实例调用 get_y() 时,它返回 0。

这是应该的吗?是否所有仅限子类的成员变量都自动设置为零,还是编译器有时会执行的那些通常发生但实际上不保证的事情之一,它们实际上应该被视为未定义?

【问题讨论】:

  • ((second_class*)a)->get_y(); 调用 未定义的行为 - 此时允许发生任何事情
  • 请注意,通过编写测试无法确定程序是否具有未定义的行为。一开始就对这个项目抱有期望是错误的。
  • 如果您正在学习 C++,请不要使用旧式转换,即 (second_class*)。请改用static_castdynamic_cast(使用多态类时)或reinterpret_cast(仅在需要时,大多数你做错了什么)。在这种情况下,您的旧式演员正在默默地进行reinterpret_cast 操作。

标签: c++


【解决方案1】:

当你投射一个指针时,它不会“转换”指向的对象(也不会以任何方式影响它)。这是一个 noop,即在运行时没有任何反应。

相反,它只是改变了被指向对象的类型。这是一个编译时概念。

因此,当你写:

(second_class*)a

你是说:“我真的知道a指向的内存是一个second_class对象,我想这样访问它”。

但它不是,它是first_class。所以访问y 数据成员没有意义。编译器最终会生成很可能最终会读取您不应该读取的内存的代码。


现在,有一种方法可以通过基类调用成员函数,即通过实际对象的基类的指针或引用。您可以阅读它(子类型、多态性和动态分派是您可能想要阅读的主题)。但在 C++ 中,它需要:

  • 您正在通过 base 类访问(而不是像您在这里所做的那样的派生类);即向上转换与向下转换。
  • 类层次结构就是这样使用的。通常,方法和析构函数将在整个层次结构中为 virtual(您的示例中没有)。

请参阅,例如:Why do we need virtual functions in C++? 以开始了解它。

【讨论】:

  • “当你投射一个指针时,(...) 它是一个 noop”。在许多情况下都是错误的。对于多重继承和多态类来说,这是不正确的。事实是:reinterpret_cast 是无操作的。 static_cast 通常可以是一个总和,dynamic_cast 包括一个查找。 C 风格的转换可以根据上下文执行任何这些操作。
  • @mirko 从技术上讲,即使是重新解释演员表也可以产生运行时效果;例如,在空 ptr 为“全 1”的硬件上(例如某些 gpu 硬件),我相信将 0 整数值重新解释为指针将返回空指针。但这越来越深奥了。
  • @Mirko 首先,如果您仔细阅读,我说的是 pointed 对象,而不是指针。你把两个独立的句子错误地合并了。其次,C 风格的强制转换不能触发dynamic_casts。至于static_cast,你指的金额是多少?因为我担心你会进入与环境相关的话题。最后,您应该注意 OP 并没有掌握基础知识。事实是:简化对教学大有帮助。
【解决方案2】:

这是应该的吗?

不,((second_class*)a)->get_y(); 调用未定义的行为

所有子类成员变量是否自动设置为零, 或者是那些通常发生但实际上没有保证的情况之一 编译器有时会做的事情

也不是,您实际上是在读取不属于该对象的内存。任何事情都可能发生(因此未定义的行为

【讨论】:

    猜你喜欢
    • 2012-02-17
    • 1970-01-01
    • 2012-02-10
    • 2012-02-02
    • 2016-02-10
    • 2022-09-24
    • 2011-05-04
    • 2013-05-08
    • 1970-01-01
    相关资源
    最近更新 更多