如何在C ++中分配子类的对象?

时间:2010-01-14 19:25:38

标签: c++ oop memory-management

我对C ++中的继承概念感到困惑,假设我们有一个名为computer的类,我们公开从计算机类继承了一个名为laptop的类。现在当我们在main函数中创建类laptop的对象时,内存中会发生什么?请解释一下。

7 个答案:

答案 0 :(得分:11)

class Computer {
  public:
   Computer() { /* whatever */}
   /* whatever */
};

class Laptop : public Computer {
   public:
    Laptop() { /* whatever */ }
  /* whatever */
};

然后......

x = new Laptop();

编译器实现的目的是:

  1. ptr = ::operator new(sizeof(Laptop))
  2. Computer::Computer(ptr)
  3. Laptop::Laptop(ptr)
  4. x = ptr
  5. 我将作为练习留给读者的堆栈。

答案 1 :(得分:4)

笔记本电脑类包含自身和计算机类中定义的属性。派生类包含基类。这就是为什么Stroustrup选择术语“基类”而不是“超类”来引用继承的类。单词super意味着继承的类更大但是反过来,继承类扩展了它继承的类。编译器分配足以容纳派生类的内存块。

答案 2 :(得分:4)

我假设你想知道多态对象的内存布局。我会尝试用肉眼展示它。考虑:

class Base()
{
public:
    virtual void foo();
    virtual void bar();
    void hello();

private:
    int variable1;
};

class Derived : public Base
{
public:
    virtual void foo();
    virtual void bar();
    void bye();

private:
    float variable2;
};

(请注意:为了清楚起见,故意省略虚拟析构函数。)

内存布局如下:

/*
Base object layout:
[vftable pointer]   (points to the 1st row in the virtual function table)
[int variable1  ]   (from Base)

Derived object layout:
[vftable pointer]   (points to the 2nd row in the virtual function table)
[int variable1  ]   (inherited from Base)
[float variable2]   (from Derived)

virtual function table layout:
[&Base::foo   ] [&Base::bar   ]
[&Derived::foo] [&Derived::bar]
*/

请注意,整个程序中只有一个用于Base和Derived的虚函数表。对于Derived的每个实例,表不会重复。相反,每个Derived实例都将一个隐藏指针保存到虚函数表的“行”中。

另请注意,hello()和bye()不会出现在vf表中,因为它们不是虚拟的。在这种情况下,正确的函数指针也可以在编译时计算出来。

此维基百科article也显示了内存布局的示例,但它更复杂,因为该示例使用多重继承。

Chip Uni使用调试器查看内存中发生的事情的想法将是一个很好的练习。

对于更高级的程序员,另一个好的练习是尝试使用结构和函数指针在C中实现多态。

答案 3 :(得分:3)

我假设笔记本电脑继承自计算机,我正在解释一般情况下会发生什么; C ++的实现细节(出于优化原因)可能与此一般解释不同。

逻辑上,Laptop类定义具有指向Computer类定义的指针。 Laptop类的实例有一个指向Laptop类定义的指针(在C ++中,很可能这只是对类方法的函数指针数组的引用)。

当笔记本电脑对象收到消息时,它首先在自己的方法表中查找相应的函数。如果不存在,则它遵循继承指针并在方法表中查找计算机类。

现在,在C ++中,大部分都发生在编译阶段,特别是我认为方法表是扁平化的,任何可以静态绑定的调用都是快捷方式。

答案 4 :(得分:2)

一个非常简单的例子可能是:

class Computer {
    char manufacturer[20];
    char type[10];
}

class Laptop : Computer {
    int runningTime;
}

如果您现在创建一个类型为computer的对象,则将分配20 + 10 = 30个字节的内存。假设在你的系统上一个整数需要4个字节,由于制造商的继承和笔记本电脑的类型,笔记本电脑的实例将需要额外的4个字节= 34个字节。分配发挥作用的地址取决于堆的当前状态。 (实际上是内存管理等) 需要将新创建的对象分配给引用变量:

i.g。

Laptop lap = new Laptop();

答案 5 :(得分:1)

答案 6 :(得分:-1)

分配内存以容纳sizeof(Object)。这包括可以继承的任何原语,如int,char等。可以在堆/堆栈上。