C++ 为什么不能将多态性与值一起使用,而与引用和指针一起使用
我发现下面的帖子 说明多态性的特点,C++必须使用指针或引用类型。 我调查了一些进一步的资源,他们都说了同样的话,但原因是一样的C++ 为什么不能将多态性与值一起使用,而与引用和指针一起使用,c++,polymorphism,C++,Polymorphism,我发现下面的帖子 说明多态性的特点,C++必须使用指针或引用类型。 我调查了一些进一步的资源,他们都说了同样的话,但原因是一样的 是否存在任何技术上的困难来支持多态性,或者是有可能的,但是C++已经决定不提供这种能力了? < p>多态性的处理问题归结为问题:因为派生对象可以使用比基类更多的内存,在自动存储中声明一个值。(即在堆栈上)导致只为基分配内存,而不是为派生对象分配内存。因此,属于派生类的对象的部分可以被切片。这就是为什么C++设计者有意识地将虚拟成员函数重路由到基类中的实现,而不能实现派
是否存在任何技术上的困难来支持多态性,或者是有可能的,但是C++已经决定不提供这种能力了?
< p>多态性的处理问题归结为问题:因为派生对象可以使用比基类更多的内存,在自动存储中声明一个值。(即在堆栈上)导致只为基分配内存,而不是为派生对象分配内存。因此,属于派生类的对象的部分可以被切片。这就是为什么C++设计者有意识地将虚拟成员函数重路由到基类中的实现,而不能实现派生类的数据成员的原因。> 困难来自这样一个事实,即您所称的对象是在自动内存(在堆栈上)中分配的,并且大小必须在编译时已知 指针的大小在编译时是已知的,不管它们指向什么,引用都是作为隐藏的指针实现的,所以不用担心 但考虑对象:BaseObject obj = ObjectFactory::createDerived();
如果createDerived()
有条件地返回派生对象,则应为obj
分配多少内存?为了克服这一问题,将返回的对象切片,并“转换*为大小已知的BaseObject
这一切都源于“为所用付费”的心态。简单的回答是因为标准规定了它。但是,允许它存在任何不可逾越的技术障碍吗 C++数据结构的大小是已知的。多态性通常要求数据结构的大小可以不同。通常,您不能在较小类型的存储器中存储不同(较大)的类型,因此存储带有额外变量的子类(或其他变大的原因)在存储中,通常不可能为父类创建 现在,我们可以绕过这个问题。我们可以创建一个比存储父类所需的缓冲区更大的缓冲区,并在该缓冲区中构造子类:但在这种情况下,将通过引用公开所述实例,并且您将仔细包装该类 这类似于
boost::any
、boost::variant
和std::string
的许多实现所使用的称为“小对象优化”的技术,我们将对象(按值)存储在类内的缓冲区中,并手动管理它们的生存期
<> P>还有一个问题:C
的值实例有virtual
方法,例如,这些方法在其他地方没有被覆盖)这是一个非常小的成本,但收益非常小
<> P>更重要的是,如果我们真的需要它,我们可以使用C++语言来模仿现有的语言特征(放置新的、引用和手动破坏),而不必强加上述成本。在C++中,当你有一个类型的对象<代码> a <代码>时,它总是表现为一个类型<代码> > <代码>的对象。这是完全正常和合乎逻辑的。我不知道它可能以任何其他方式来运行。所以,不清楚某人决定“不提供”的“能力”。 在C++中多态性意味着一件事:通过多态表达式的虚函数调用根据该表达式的动态类型(与非虚拟函数的静态类型相反)来解决。这就是它的全部内容。 <>多态在C++中总是按照上述规则工作的,它通过指针工作。它通过引用来工作。它通过直接对象(如你所说的“值”)来工作。因此,C++中的多态性只与指针和引用一起工作并不正确。它与“值”一起工作。同样,它们都遵循同样的规则,如上所述 然而,对于直接对象(“值”),其动态类型始终与静态类型相同。因此,即使多态性适用于直接值,它也不能证明任何真正的“多态性”。具有多态性的直接对象的行为与不具有多态性的直接对象的行为相同。因此,直接对象的多态性是退化的、琐碎的多态性。它仅在概念上存在。这也是完全合乎逻辑的:类型为
A
的对象应表现为类型为A
的对象。否则它怎么可能存在呢阿维
为了观察实际的非退化多态性,需要一个静态类型与其动态类型不同的表达式。当静态类型A
的表达式行为时(关于虚拟函数调用),可以观察到非平凡多态性作为不同类型的对象B
。为此,静态类型A
的表达式必须实际引用类型B
的对象。这只能通过指针或引用来实现