我刚刚发现我对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();
谢谢!
答案 0 :(得分:13)
根据Base *ptr = new Derived();
类分配Derived
内存。 ptr
指向对象,但指示编译器仅“授予”Base
类中声明的对象成员的“访问权限”(可见性)。
当然,与指针ptr
相关联的存储器是相同的,即与指示它指向的对象无关。通常,“指针对象”的大小在CPU架构上是恒定的,例如32位/ 64位(例如,在嵌入式设备上更小)。
对于Derived *ptr = new Base();
:不,这是无效的。
类Derived
不仅仅是一个类Base
,而是从Base
定义为派生:因此,指向Derived
的指针实例无法将对象实例仅分配给类Base
的对象实例。
您可以考虑仔细阅读非常好的维基百科贡献on Polymorphism和Inheritance。
答案 1 :(得分:4)
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。
Derived
是Base
的子类型。这意味着Base
可以做的所有事情,Derived
也可以。通常,Derived
比Base
更具体:它适用于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]的情况下,才能将值赋给变量。由于Derived
是Base
,Derived*
是Base*
- 所以这不是冲突的,但反过来却不是真的。
我强烈建议您阅读the comment以了解逻辑