我确实在 StackOverflow 上发现了一些标题相似的问题,但是当我阅读答案时,他们关注的是问题的不同部分,这些部分非常具体(例如 STL/容器)。
有人可以告诉我,为什么必须使用指针/引用来实现多态性?我可以理解指针可能会有所帮助,但肯定引用仅区分按值传递和按引用传递?
当然,只要您在堆上分配内存,以便您可以进行动态绑定,那么这就足够了。明显不是。
原文由 user997112 发布,翻译遵循 CC BY-SA 4.0 许可协议
我确实在 StackOverflow 上发现了一些标题相似的问题,但是当我阅读答案时,他们关注的是问题的不同部分,这些部分非常具体(例如 STL/容器)。
有人可以告诉我,为什么必须使用指针/引用来实现多态性?我可以理解指针可能会有所帮助,但肯定引用仅区分按值传递和按引用传递?
当然,只要您在堆上分配内存,以便您可以进行动态绑定,那么这就足够了。明显不是。
原文由 user997112 发布,翻译遵循 CC BY-SA 4.0 许可协议
“当然,只要您在堆上分配内存” - 分配内存的位置与它无关。这都是关于语义的。举个例子:
Derived d;
Base* b = &d;
d
在堆栈上(自动内存),但多态性仍然适用于 b
。
如果您没有基类指针或对派生类的引用,则多态性不起作用,因为您不再拥有派生类。拿
Base c = Derived();
c
对象不是 Derived
,而是 Base
,因为 切片。所以,从技术上讲,多态性仍然有效,只是你不再有 Derived
对象可谈。
现在拿
Base* c = new Derived();
c
只是指向内存中的某个地方,你并不关心它实际上是一个 Base
还是一个 Derived
,但是调用一个 virtual
方法将动态解析。
原文由 Luchian Grigore 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.5k 阅读
3 回答461 阅读✓ 已解决
在 C++ 中,对象始终具有在编译时已知的固定类型和大小,并且(如果可以并且确实获取了其地址)在其生命周期内始终存在于固定地址。这些是从 C 继承的特性,有助于使这两种语言都适用于低级系统编程。 (不过,所有这些都受制于 as-if, 规则:只要可以证明它对保证的符合标准的程序的任何行为没有可检测的影响,符合标准的编译器就可以自由地对代码做任何事情。按标准。)
C++ 中的
virtual
函数被定义为(或多或少,不需要极端的语言律师)基于对象的运行时类型执行;当直接在对象上调用时,它将始终是对象的编译时类型,因此当以这种方式调用virtual
函数时没有多态性。请注意,这不一定是这种情况:具有
virtual
函数的对象类型通常在 C++ 中实现,每个对象指针指向virtual
函数表,这是唯一的到每种类型。如果这样倾向于,C++ 的一些假设变体的编译器可以实现对象的赋值(例如Base b; b = Derived()
)作为复制对象的内容和virtual
表指针连同它,如果Base
和Derived
大小相同,这将很容易工作。在两者大小不同的情况下,编译器甚至可以插入暂停程序任意时间的代码,以便重新排列程序中的内存并以可能的方式更新对该内存的所有可能引用证明对程序的语义没有可检测的影响,如果找不到这样的重新排列,则终止程序:但是,这将非常低效,并且不能保证永远停止,显然不是赋值运算符想要的特性有。因此,代替上述内容,C++ 中的多态性是通过允许对对象的引用和指针来引用和指向其声明的编译时类型及其任何子类型的对象来实现的。当通过引用或指针调用
virtual
函数时,编译器无法证明引用或指向的对象是具有特定已知实现的运行时类型virtual
函数,编译器插入代码来查找正确的virtual
函数来调用运行时。它也不必是这样:引用和指针可以被定义为非多态的(不允许它们引用或指向其声明类型的子类型)并迫使程序员想出实现多态的替代方法.后者显然是可能的,因为它一直在 C 中完成,但在这一点上,根本没有太多理由拥有一门新语言。总之,C++ 的语义被设计为允许面向对象多态性的高级抽象和封装,同时仍然保留使其适用于的特性(如低级访问和显式内存管理)低水平发展。您可以轻松设计一种具有其他语义的语言,但它不会是 C++,并且会有不同的优点和缺点。