为什么基类指针始终指向基类,即使它包含派生类对象地址?

时间:2014-06-27 17:47:58

标签: c++ inheritance

我在同一个问题上已经完成了一些以前的帖子,但我找不到任何令人满意的答案。 为什么基类指针始终指向基类,即使它保存派生类对象的地址?我知道,由于这个原因,virtual关键字出现在图片中,但我无法弄清楚为什么基类指针始终指向基类,即使它保存派生类的地址。有人可以解释一下吗?

class base
{
  public:void fn()
  {
    cout << "I am in base" << endl;
  }
};

class derived : public base
{
  public:void fn()
  {
    cout << "I am in derived"<< endl;
  }
};

int main()
{
  base *p;     // creating pointer object for base class
  derived obj; // creating object for derived class
  p=&obj;      // storing object of derived class in pointer
  p->fn();     // If pointer has address of derived class object
               // then why still it print base class function
               // why we need to use virtual keyword to print
               // derived class function?
}

3 个答案:

答案 0 :(得分:3)

派生类的对象始终在其中的某处包含基类类型的对象。这被称为“基类子对象”。如果p的类型为base*,那么当p设置为指向derived类型的对象时,它实际上设置为指向base子对象那个derived对象。

此行为确保即使指针实际指向派生类的对象,也可以从指针调用基类非静态成员函数。因此,实现不会 在运行时查找p是指向完整的base对象还是完整的derived对象;无论如何,它仍然指向一个base对象(可能只是一个基类子对象)。

为了确保即使您使用指向基类的指针调用派生类的函数实现,编译器也必须在运行时生成查找的附加代码,无论是否指针指向完整的base对象或完整的derived对象。如果要强制它执行此操作,请标记函数virtual。如果没有,那么当您不需要时,C ++不会强迫您支付虚拟呼叫的费用。

答案 1 :(得分:0)

  

为什么基类指针始终指向基类,即使它保存派生类对象地址?

原因是编译器忽略指针p内容,并选择与类型<匹配的成员函数(如果未声明virtual) / em>指针。

答案 2 :(得分:0)

因为你没有让fn虚拟。由于p指向base,因此调用base的方法。如果您想要具有其他行为,请将base中的fn声明为虚拟。

设置p时,编译器无法知道p指向derived。在这个简单的情况下它可以,但在其他情况下,例如当调用接受指向基础对象的指针的函数时,它不能:

考虑简单的功能

void doStuff(Base* base)
    {
    base->fn();
    }

编译doStuff时,编译器无法知道最初指向derived对象的基础。所以为了保持一致,最好不要使用这个类型在给出的简单案例中已知的事实。

要跟踪指针所指向的“{1}”类型,可以将所考虑的函数声明为 virtual 。这通常会为从base派生的所有类添加一个不可见的指针。该指针指向 vtable ,而 vtable 又包含指向所有虚拟方法的指针

为什么默认情况下这些方法不是虚拟的?因为它添加了一个不可见的成员,

  • 占用一些空间
  • 将破坏使用POD指定的ABI:s
  • 有时将纯结构转储到磁盘是有意义的。但是不应该将指针写入磁盘。