声明指向基类和派生类的指针
Posted
技术标签:
【中文标题】声明指向基类和派生类的指针【英文标题】:Declaring pointer to base and derived classes 【发布时间】:2010-01-12 02:35:12 【问题描述】:我刚刚发现我对 C++ 中的一个基本问题感到困惑
class Base
;
class Derived : public Base
Base *ptr = new Derived();
这是什么意思? ptr 是指向基类还是派生类?在这一行,为 ptr 分配了多少内存?基于 Derived 或 Base 的大小?
这和下面有什么区别:
Base *ptr = new Base();
Derived *ptr = new Derived();
有这样的案例吗?
Derived *ptr = new Base();
谢谢!
【问题讨论】:
【参考方案1】:对于Base *ptr = new Derived();
,内存是根据Derived
类分配的。 ptr
指向该对象,但指示编译器仅“授予访问权限”(可见性)对在 Base
类中声明的对象成员。
当然,与指针ptr
关联的内存是相同的,即独立于它被指示指向的对象。通常,“指针对象”的大小在 CPU 架构上是恒定的,例如32 位 / 64 位(例如,在嵌入式设备上更小)。
对于Derived *ptr = new Base();
:不,这是无效的。
Derived
类不仅仅是一个Base
类,而是从Base
定义为派生:因此,指向Derived
对象实例的指针实例不能只是分配给Base
类的对象实例。
您可以考虑仔细阅读非常好的***贡献 on Polymorphism 和 Inheritance。
【讨论】:
那么 *ptr 的类型是什么?基础还是派生?将它作为指向 Base 的指针有什么好处? @skydoor:它与多态性有关(请参阅en.wikipedia.org/wiki/…):您可以有不同的派生类共享一个基类。 @skydoor-它更加灵活,因为 Base 指针可以指向从 Base 类派生的 任何 对象。【参考方案2】:Polymorphism
ptr 是一个指针;无论它指向什么,它都有相同的大小。
【讨论】:
【参考方案3】:在 32 位系统上,为 ptr
分配了 4 个字节的堆栈空间。在 64 位系统上,它将是 8 个字节。 (假设编译器没有决定将它留在寄存器中并且根本不分配任何堆栈空间)。
您可以让指向Base
的指针指向Derived
的原因是OOP 的基本原则之一——多态性。 Derived
是 Base
。你可以把它贴在任何可以使用Base
的地方。
您的最后一行 (Derived *ptr = new Base();
) 无效,因为 Base
不是 Derived
。
【讨论】:
是的。我假设这是一个函数局部变量。【参考方案4】:要了解 C++ 的类型系统,了解 静态 类型和 动态 类型之间的区别很重要。在您的示例中,您定义了类型 Base 和 Derived 以及具有 static 类型 Base *ptr /strong>。
现在,当您调用 new Derived()
时,您会返回一个 static 和 dynamic 类型为 Derived * 的指针。由于 Derived 是 Base 的子类型,因此可以将其隐式转换为 Base * 的 static 类型并分配给ptr
作为 static 类型现在匹配。 dynamic 类型仍然是 Derived *,但是如果您通过 ptr
调用 Base 的任何虚函数,这非常重要,因为调用虚函数总是基于对象的动态类型,而不是静态类型。
【讨论】:
【参考方案5】:您的问题涉及面向对象编程中最重要的部分之一:polymorphism。
Derived
是Base
的子类型。这意味着Base
可以做的所有事情,Derived
也可以做。通常,Derived
比 Base
更具体:它适用于 Base
所做的一个子集,但它比 Base
所做的要好得多。
想一个例子。
考虑编写一个图形程序。你可能有一个类ClosedShape
,其中有一个方法fill()
。可以创建一个非常通用的方法来填充任何封闭的形状……但通常,该方法会占用内存,而且速度可能很慢。
你可能有另一个课程,Square
。现在,填充正方形非常容易且非常快速:它是两个嵌套的 for 循环。由于Square
做了ClosedShape
所做的一切,它可以从ClosedShape
继承。
为什么多态很重要?想想许多不同类型的ClosedShape
:三角形、六边形等等。如果你想填写所有这些,只需:
for (i=0; i<num; i++)
cs[i].fill();
他们都将使用自己版本的fill()
!
【讨论】:
不。继承与方法和字段查找有关。你描述的是多态性。【参考方案6】:对于基础 *ptr = new Derived();内存是根据派生类分配的。 ptr 指向该对象,但编译器被指示只“授予访问”(可见性)到在基类中声明的对象成员。
当然,与指针 ptr 关联的内存是相同的,即独立于它被指示指向的对象。通常,“指针对象”的大小在 CPU 架构上是恒定的,例如32 位 / 64 位(例如,在嵌入式设备上更小)。
For Derived *ptr = new Base();: 不,这是无效的。
Class Derived 不仅是 Base 类,而且被定义为从 Base 派生:因此,不能将指向 Derived 对象实例的指针实例仅分配给 Base 类的对象实例。
【讨论】:
【参考方案7】:Derived
对象被附加到Base
对象的末尾,所以Derived
的前缀[位]实际上是Base
,所以分配Derived*
对象没有问题到 Base*
变量。访问Base
的任何Derived
对象的字段/方法是完全安全的。
但是 - 对面不正确。如果您将Base*
的地址分配给Derived*
变量,然后访问Derived
[不在Base
中] 的字段之一,您将退出分配的空间。
打字推理:
另外请注意,只有当变量的类型正确且无需强制转换 [c++ is static typing langauge] 时,才能将值分配给变量。因为Derived
是Base
,Derived*
是Base*
- 所以这并不矛盾,但反过来就不正确了。
我强烈建议阅读the comment 以了解其逻辑
【讨论】:
以上是关于声明指向基类和派生类的指针的主要内容,如果未能解决你的问题,请参考以下文章