全局函数与成员函数 我最近一直在玩C++,想知道为什么有这么多的全局函数。然后我开始考虑用c#编程,以及成员函数是如何存储的,所以我想我的问题是我是否有: public class Foo { public void Bar() { ... } } 公开课Foo{ 公共空栏(){…} }

全局函数与成员函数 我最近一直在玩C++,想知道为什么有这么多的全局函数。然后我开始考虑用c#编程,以及成员函数是如何存储的,所以我想我的问题是我是否有: public class Foo { public void Bar() { ... } } 公开课Foo{ 公共空栏(){…} },c#,c++,memory-management,C#,C++,Memory Management,然后我做了一些愚蠢的事情,比如在列表中添加1000000个Foo;这是否意味着内存中有1000000个Foo对象,每个对象都有自己的Bar()函数?还是发生了更聪明的事情 谢谢。没有,只有一个实例。一个类的所有实例都指向一个对象,该对象包含所有实例方法,这些实例方法采用一个隐式的第一个参数,亲切地称为this。在实例上调用实例方法时,该实例的指针作为第一个参数传递给该方法。这就是该方法如何知道该实例的所有实例字段和属性 有关详细信息,请参阅 当然,virtual方法使这一点变得复杂。CLR vi

然后我做了一些愚蠢的事情,比如在列表中添加1000000个Foo;这是否意味着内存中有1000000个Foo对象,每个对象都有自己的Bar()函数?还是发生了更聪明的事情


谢谢。

没有,只有一个实例。一个类的所有实例都指向一个对象,该对象包含所有实例方法,这些实例方法采用一个隐式的第一个参数,亲切地称为
this
。在实例上调用实例方法时,该实例的
指针作为第一个参数传递给该方法。这就是该方法如何知道该实例的所有实例字段和属性

有关详细信息,请参阅


当然,
virtual
方法使这一点变得复杂。CLR via C#将为您阐明这一区别,如果您对这一主题感兴趣,我们强烈推荐您。无论如何,每个实例方法仍然只有一个实例。问题在于如何解决这些方法。

不,只有一个实例。一个类的所有实例都指向一个对象,该对象包含所有实例方法,这些实例方法采用一个隐式的第一个参数,亲切地称为
this
。在实例上调用实例方法时,该实例的
指针作为第一个参数传递给该方法。这就是该方法如何知道该实例的所有实例字段和属性

有关详细信息,请参阅


当然,
virtual
方法使这一点变得复杂。CLR via C#将为您阐明这一区别,如果您对这一主题感兴趣,我们强烈推荐您。无论如何,每个实例方法仍然只有一个实例。问题在于如何解决这些方法。

实例方法只是一个带有隐藏的
参数的
静态
方法


virtual
方法稍微复杂一些)

实例方法只是一个
static
方法,带有一个隐藏的
这个
参数


<>(<代码>虚拟<代码>方法有点复杂)C++中的

成员函数通常不需要任何对象存储(异常-代码>虚拟/Cuff>函数-在下一段中讨论)。通常,在使用函数的每一点上,编译器都会生成特定于CPU的机器代码来直接调用该函数,对于内联函数,可以避免调用,并且函数的影响可以最佳地集成到调用方的代码中(对于诸如“getter和setter”之类的小函数,可以快10倍左右)只需读取或写入一个成员变量)

对于那些有一个或多个虚函数的类,每个对象都有一个额外的指针,指向每个类的函数指针表和其他信息。因此,每个对象都会随着指针的大小而增长,通常为4或8个字节


<>处理你最初的观察:C++有更多非成员函数(通常在<>代码STD命名空间),但是命名空间比这个类更好地服务于这个目的。实际上,名称空间实际上是“静态”函数和数据的逻辑接口,这些函数和数据可以跨越许多“物理”头文件。为什么程序的逻辑API会受到与物理文件及其对构建时间、文件修改时间戳触发的生成工具等的影响相关的考虑因素的影响?在命名空间位于一个报头的琐碎情况下,C++可以使用类或结构来对相同的声明进行范围化,但这并不方便,因为它防止使用命名空间别名,<代码>使用< /COD>命名空间,Koenig lookup用于隐式搜索与函数参数名称空间匹配的名称空间-强制在每个使用点使用非常显式的前缀。它也给用户一个错误的印象,即用户想要从内容中实例化一个对象。C++中的

< P>一个成员函数通常不需要任何对象存储(异常-代码>虚拟/代码>函数-在下一段中讨论)。通常,在使用函数的每一点上,编译器都会生成特定于CPU的机器代码来直接调用该函数,对于内联函数,可以避免调用,并且函数的影响可以最佳地集成到调用方的代码中(对于诸如“getter和setter”之类的小函数,可以快10倍左右)只需读取或写入一个成员变量)

对于那些有一个或多个虚函数的类,每个对象都有一个额外的指针,指向每个类的函数指针表和其他信息。因此,每个对象都会随着指针的大小而增长,通常为4或8个字节

<>处理你最初的观察:C++有更多非成员函数(通常在<>代码STD命名空间),但是命名空间比这个类更好地服务于这个目的。实际上,名称空间实际上是“静态”函数和数据的逻辑接口,这些函数和数据可以跨越许多“物理”头文件。为什么程序的逻辑API会受到与物理文件及其对构建时间、文件修改时间戳触发的生成工具等的影响相关的考虑因素的影响?在命名空间位于一个报头的琐碎情况下,C++可以使用类或结构来对相同的声明进行范围化,但这并不方便,因为它防止使用命名空间别名,<代码>使用< /COD>命名空间,Koenig lookup用于隐式搜索与函数参数名称空间匹配的名称空间-强制在每个使用点使用非常显式的前缀。它还给人一种错误的印象,即用户打算从内容中实例化一个对象。