需要一些帮助来了解类继承(C ++)

时间:2019-04-06 22:22:36

标签: c++

我正试图出于自己的目的扩展其他人的API,并试图在这种情况下绕过类继承。

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


    #include 

    class first_class {
    public:
        first_class() {};
    };

    class second_class : first_class {
    private:
        int y;

    public:
        int get_y() { return y; }
        second_class() {
            y=99;
        }
    };

    int main() {
        first_class* a = new first_class();
        second_class* b = new 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。

那是应该期待的吗?是否所有仅纯子类的成员变量都自动设置为零,还是编译器有时会做的那些通常会发生但实际上并没有保证的事情之一,而实际上应该将它们视为未定义?

2 个答案:

答案 0 :(得分:4)

当您投射指针时,它不会“转换”指向的对象(也不会以任何方式影响它)。这是一个小问题,即在运行时什么也没有发生。

相反,它只是简单地更改了指向对象的 type 类型。这是一个编译时概念。

因此,当您编写时:

(second_class*)a

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

但不是,它是first_class。因此,访问y数据成员没有任何意义。编译器最终将生成最有可能最终读取不需要的内存的代码。


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

  • 您正在通过 base 类进行访问(而不是像您在此处那样派生的类);即向上转换还是向下转换。
  • 该类层次结构应以这种方式使用。通常,方法和析构函数将在整个层次结构中为virtual(在示例中没有)。

例如,参见:Why do we need virtual functions in C++?,开始学习它。

答案 1 :(得分:2)

  

那应该是什么?

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

  

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

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