声明指向基类和派生类的指针

时间:2010-01-12 02:35:12

标签: c++ inheritance polymorphism

我刚刚发现我对C ++中的一个基本问题感到困惑

class Base {

};

class Derived : public Base {

}

Base *ptr = new Derived(); 

这是什么意思? ptr指向Base类或Derived类?在这一行,为ptr分配了多少内存?基于Derived或Base的大小?

这与以下之间有什么区别:

Base *ptr = new Base();
Derived *ptr = new Derived();

有这样的情况吗?

Derived *ptr = new Base();

谢谢!

7 个答案:

答案 0 :(得分:13)

根据Base *ptr = new Derived();类分配Derived内存。 ptr指向对象,但指示编译器仅“授予”Base类中声明的对象成员的“访问权限”(可见性)。

当然,与指针ptr相关联的存储器是相同的,即与指示它指向的对象无关。通常,“指针对象”的大小在CPU架构上是恒定的,例如32位/ 64位(例如,在嵌入式设备上更小)。

对于Derived *ptr = new Base();:不,这是无效的。

Derived不仅仅是一个类Base,而是从Base定义为派生:因此,指向Derived的指针实例无法将对象实例仅分配给类Base的对象实例。


您可以考虑仔细阅读非常好的维基百科贡献on PolymorphismInheritance

答案 1 :(得分:4)

Polymorphism

ptr是一个指针;无论它指向什么,它都具有相同的大小。

答案 2 :(得分:4)

在32位系统上,为ptr分配了4个字节的堆栈空间。在64位系统上,它将是8个字节。 (假设编译器没有决定将它留在寄存器中而根本没有分配任何堆栈空间。)

您可以让指向Base的指针指向Derived的原因是OOP - 多态性的基本原则之一。 Derived Base。您可以将其粘贴在可以使用Base的任何位置。

您的上一行(Derived *ptr = new Base();)无效,因为Base 一个Derived

答案 3 :(得分:2)

要理解C ++的类型系统,了解静态类型和动态类型之间的区别非常重要。在您的示例中,您定义了 Base Derived 类型以及 static 类型 Base的变量ptr *

现在,当您致电new Derived()时,您会收到一个指针,其中包含静态动态类型的派生* 。由于派生 Base 的子类型,因此可以将其隐式转换为 Base * 静态类型并分配给{em}静态类型的ptr现在匹配。 动态类型仍然是派生* 但是,如果您通过ptr调用 Base 的任何虚拟功能,这非常重要虚函数始终基于对象的动态类型,而不是 static 类型。

答案 4 :(得分:1)

您的问题出现在面向对象编程的一个最重要的部分:polymorphism

DerivedBase的子类型。这意味着Base可以做的所有事情,Derived也可以。通常,DerivedBase更具体:它适用于Base所做的一部分,但它比Base做得更好。

想一个例子。

考虑编写图形程序。您可能有一个类ClosedShape及其中的方法fill()。可以创建一个非常通用的方法来填充任何封闭的形状...但通常,该方法将占用内存,而且可能很慢。

您可能有另一个班级Square。现在,填充正方形非常简单且非常快:它是两个嵌套的循环。由于Square执行ClosedShape所做的所有事情,因此它可以从ClosedShape继承。

为什么多态性很重要?想想许多不同类型的ClosedShape:三角形,六边形等等。如果你想填写所有这些,只需:

for (i=0; i<num; i++) {
    cs[i].fill();
}

他们都会使用自己的版本fill()

答案 5 :(得分:0)

For Base * ptr = new Derived();内存根据Derived类分配。 ptr指向该对象,但指示编译器仅“授予访问”(可见性)给在Base类中声明的对象的成员。

当然,与指针ptr相关联的存储器是相同的,即与指示它指向的对象无关。通常,“指针对象”的大小在CPU架构上是恒定的,例如32位/ 64位(例如,在嵌入式设备上更小)。

For Derived * ptr = new Base();: no,这是无效的。

Class Derived不仅仅是一个类Base,而是定义为从Base派生:因此,Derived对象实例的指针实例不能只分配给Base类的对象实例。

答案 6 :(得分:0)

Derived对象附加到Base对象的末尾,因此Derived的前缀[以位为单位]实际上是Base,所以没有将Derived*对象分配给Base*变量的问题。访问Base对象的Derived个字段/方法非常安全。

然而 - 对立不是真的。如果您将Base*的地址分配给Derived*变量,然后访问Derived [不在Base]中的某个字段,您将退出分配空间。

打字推理:
另请注意,只有在没有强制转换[c ++ is static typing langauge]的情况下,才能将值赋给变量。由于DerivedBaseDerived*Base* - 所以这不是冲突的,但反过来却不是真的。

我强烈建议您阅读the comment以了解逻辑