我最近一直在玩c ++,并想知道为什么会有这么多全局函数。然后我开始考虑用c#编程以及如何存储成员函数,所以我想我的问题是我是否有:
public class Foo { public void Bar() { ... } }
然后我做了一些愚蠢的事情,就像在列表中添加1,000,000 Foo的一样;这是否意味着我有1,000,000个 Foo 对象坐在内存中,每个对象都有自己的Bar()函数?还是会发生更聪明的事情?
感谢。
答案 0 :(得分:8)
不,只有一个例子。类的所有实例都指向一个对象,该对象包含采用隐式第一个参数亲切地称为this
的所有实例方法。在实例上调用实例方法时,该实例的this
指针将作为第一个参数传递给该方法。这就是该方法如何知道该实例的所有实例字段和属性。
有关详细信息,请参阅CLR via C#。
这当然是virtual
方法的复杂化。 CLR通过C#将为您说出区别,如果您对此主题感兴趣,则高度推荐。无论哪种方式,每个实例方法仍然只有一个实例。问题在于如何解决这些方法。
答案 1 :(得分:3)
实例方法只是一个带有隐藏static
参数的this
方法。
(virtual
方法稍微复杂一些)
答案 2 :(得分:1)
在C ++中,成员函数通常不需要任何每对象存储(异常 - virtual
函数 - 将在下一段中讨论)。通常,在使用函数的每个点上,编译器生成特定于CPU的机器代码以直接调用该函数,对于内联函数,可以避免调用,并且函数的影响可以最佳地集成到调用者的代码中(可以是〜对于诸如“getters and setters”之类的小函数来说,只需读取或写入一个成员变量就快10倍。
对于那些具有一个或多个虚函数的类,每个对象都有一个额外的指针指向每个类的函数指针表和其他信息。因此,每个对象都以指针的大小增长 - 通常为4或8个字节。
解决您的原始观察:C ++有更多非成员函数(通常在std
命名空间中),但是命名空间最好比类更好地服务于此目的。实际上,命名空间实际上是“静态”功能和数据的逻辑接口,可以跨越许多“物理”头文件。为什么程序的逻辑API会因与物理文件相关的注意事项及其对构建时间的影响,文件修改时间戳触发的make工具等而受到影响?在命名空间位于一个标头中的简单情况下,C ++可以使用类或结构来定义相同的声明,但这样做不太方便,因为它阻止使用命名空间别名,using
命名空间和Koenig查找来隐式搜索名称空间匹配函数参数的名称空间 - 在每个使用点强制使用非常明确的前缀。它还给出了错误的印象,即用户打算从内容中实例化对象。