为什么函数不是对象?

Sha*_*adi 33 c++ function object functor

我在标准n4296(草案)§1.8第7页中读到:

一个对象是存储的区域.[注意:函数不是对象,无论它是否以对象的方式占用存储. - 尾注]

我在网上花了几天寻找这种排斥的充分理由,没有运气.也许是因为我不完全理解对象.所以:

  1. 为什么函数不是对象?它有何不同?
  2. 这与仿函数(函数对象)有什么关系吗?

Jer*_*fin 43

很多不同之处在于指针和寻址.在C++中,指向函数和指向对象的指针是完全不同的东西.

C++要求您可以将指向任何对象类型的指针void转换为指针,然后将其转换回原始类型,结果将等于您启动的指针².换句话说,无论它们究竟是如何做的,实现都必须确保从指针到对象类型到指针到无效的转换是无损的,因此无论原始内容是什么,它包含的任何信息都可以重新创建,以便您可以通过从转换T*void *返回来获取与开始时相同的指针T*.

不是一个指向函数的指针,虽然真正的-如果你把一个指向函数的指针,将其转换为void *,然后将其转换回一个指向函数的指针,你可能会失去在这个过程中的一些信息.您可能无法取回原始指针,并且取消引用您返回的内容会为您提供未定义的行为(简而言之,请勿执行此操作).

但是,对于它的价值,您可以将指向一个函数的指针转换为指向不同类型函数的指针,然后将该结果转换回原始类型,并保证结果与您启动时的结果相同用.

尽管与手头的讨论并不特别相关,但还有一些其他差异可能值得注意.例如,您可以复制大多数对象 - 但不能复制任何功能.

至于与函数对象的关系:嗯,除了一点之外真的没有太多:函数对象支持看起来像函数调用的语法 - 但它仍然是一个对象,而不是一个函数.因此,指向函数对象的指针仍然是指向对象的指针.例如,如果将一个转换为void *,然后将其转换回原始类型,则仍然可以保证返回原始指针值(使用指向函数的指针时不会这样).

至于为什么指向函数的指针(至少可能)与指向对象的指针不同:它的一部分归结为现有系统.例如,在MS-DOS(以及其他)上,有四个完全独立的内存模型:小型,中型,紧凑型和大型.小型号使用16位寻址功能或数据.中,数据使用16位地址,代码使用20位地址.紧凑反转(代码为16位地址,数据为20位地址).大量使用20位地址代码和数据.因此,在紧凑型或中型模型中,在指向代码和指向函数的指针之间进行转换确实会导致问题.

最近,相当数量的DSP使用完全独立的存储器总线来代码和数据(和MS-DOS内存模型一样)它们通常是不同的宽度,两者之间的转换可能并且确实丢失了信息.


  1. 这些特殊规则来自C的C++,所以在C中也是如此,无论价值多少.
  2. 虽然它不是直接需要的,但就事情的运作方式而言,对于从原始类型到指针char和返回的转换,几乎同样适用于任何值得的东西.

  • @Kevin:我考虑过这样做,但我认为它可能会做更多的混淆而不是照亮.问题是很多人用它来引用像当前的x86/x64这样的东西,其中数据和代码具有单独的*缓存*,但仍然存在于相同的实际内存中.在我正在谈论的DSP上,他们有独立的内存总线与完全独立的内存阵列交谈(不是说这意味着它不是*哈佛架构,但它与使用该术语的人数不同). (3认同)
  • 然后有一天有人必须设计和实现`dlsym()`而且事情变得非常毛茸茸. (2认同)

pul*_*ion 5

为什么函数不是对象?它有何不同?

要理解这一点,让我们从涉及的抽象方面从下到上移动.所以,你有你的地址空间,你可以通过它来定义内存的状态,我们必须记住,从根本上说,这是你操作的状态.

好吧,让我们在抽象方面略微提高一点.我还没有考虑编程语言强加的任何抽象(如对象,数组等),但作为一个外行人,我想记录一部分内存,让我们调用它Ab1,另一个调用Ab2.

两者都有的状态根本,但我打算操纵/利用状况的不同.

不同......为什么和如何?

为什么?

因为我的要求(例如,执行添加2个数字并存储结果).我将使用use Ab1作为长使用状态和Ab2相对较短的使用状态.所以,我将创建一个状态Ab1(与2号添加),然后使用这个状态来填充一些国家Ab2(临时复制他们)并进行进一步操作Ab2(添加它们)和由此产生的部分保存Ab2Ab1(该添加结果).邮件Ab2变得无用,我们重置其状态.

怎么样?

我将需要对这两个部分进行一些管理,以便跟踪要从哪个单词中选择Ab1和复制到Ab2等等.在这一点上,我意识到我可以使它能够执行一些简单的操作,但严重的事情需要一个规范的规范来管理这个内存.

因此,我寻找这样的管理规范,结果发现存在各种这些规范(一些具有内置存储器模型,另一些提供了自己管理存储器的灵活性),具有更好的设计.实际上因为它们(甚至没有规定如何直接管理内存)已经成功地定义了这个长期存储的封装以及如何以及何时创建和销毁它的规则.

同样的,Ab2但他们呈现它的方式让我觉得这有很大的不同Ab1.事实上,事实证明是.它们使用堆栈进行状态操作Ab2并从堆中保留内存Ab1.Ab2一段时间后死亡.(完成执行后).

此外,你的方式定义是做什么用Ab2的通过又称为另一个存储部分完成Ab2_Code和规范Ab1同样涉及Ab1_Code

我会说,这太棒了!我得到了很多便利,这让我可以解决很多问题.

现在,我仍然从一个外行人的角度来看,所以我不会感到惊讶真的经历了这一切的思考过程,但如果你自上而下地质疑事情,事情可能会有点难以透视.(我怀疑这就是你的情况)

顺便说一句,我忘了提,Ab1被称为对象正式和Ab2一个函数栈,同时Ab1_Code类的定义Ab2_Code函数定义代码.

正是由于PL所施加的这些差异,你才发现它们是如此不同.(你的问题)

注意:不要把我的表现Ab1/ Object作为一项长期的存储抽象的规则或具体的东西-它是从外行的角度.编程语言在管理对象的生命周期方面提供了更大的灵活性.因此,可以部署对象,Ab1但它可以更多.

这与仿函数(函数对象)有什么关系吗?

请注意,第一部分答案通常适用于许多编程语言(包括C++),这部分必须专门针对C++(您引用的规范).所以你有一个指向函数的指针,你也可以有一个指向对象的指针.它只是C++定义的另一种编程结构.注意,这是关于具有指针Ab1,Ab2以操纵它们,而不是具有彼此明显不同的抽象作用于其上.

你可以在这里阅读它的定义和用法:

C++ Functors - 及其用途

  • 你的前两段很难阅读,可以用几句话来概括.我猜你没有得票,因为大多数人只是在达到"_Differently ...... Why and How?_"之前就停止阅读. (3认同)