2010-11-29 3 views
1

В последнее время я играл с C++ и задавался вопросом, почему так много глобальных функций. Тогда я начал думать о программировании в C# и как функции-члены сохраняются, так что я думаю, мой вопрос, если у меня есть:Глобальные против функций-членов

 
public class Foo { 
    public void Bar() { ... } 
} 

, а затем я сделать что-то глупое, как добавление 1000000 Foo-х в список; это означает, что у меня есть 1 000 000 Foo объектов, сидящих в памяти, каждый со своей собственной функцией Bar()? Или происходит что-то гораздо более умное?

Спасибо.

ответ

8

Нет, есть только один случай. Все экземпляры класса указывают на объект, который содержит все методы экземпляра, которые принимают неявный первый параметр, нежно называемый this. Когда вы вызываете метод экземпляра в экземпляре, в качестве первого параметра для этого метода передается указатель this для этого экземпляра. Именно так метод знает все поля и свойства экземпляра для этого экземпляра.

Подробнее см. CLR via C#.

Это, конечно, сложный метод virtual. CLR через C# прописал различие для вас и высоко рекомендуется, если вас интересует эта тема. В любом случае, все еще существует только один экземпляр каждого метода экземпляра. Проблема заключается в том, как разрешаются эти методы.

+0

Это то же самое, что бы произошло, если бы у меня был, скажем, вектор ? – aligray 2010-11-29 04:31:44

+1

@aligray: Общие классы, которые имеют параметры типа, которые являются классами, в результате чего генерируется только одна копия генерируемого кода. Так, да, да. – siride 2010-11-29 06:18:55

3

Метод экземпляра - это просто метод static со скрытым параметром this.

(virtual методы являются немного более сложным)

1

В C++ функции-члена не обычно требует какого-либо объекта в-хранилище (исключение - virtual функции - обсуждается в следующем абзаце). Как правило, в каждой точке, где используется функция, компилятор генерирует машинный код, специфичный для процессора, для прямого вызова этой функции, а для встроенных функций вызов можно избежать, и влияние функции может быть оптимально интегрировано в код вызывающего абонента (который может быть ~ 10 раз быстрее для небольших функций, таких как «геттеры и сеттеры», которые просто читают или записывают одну переменную-член).

Для тех классов, которые имеют одну или несколько виртуальных функций, каждый объект будет иметь один дополнительный указатель на таблицу классов указателей функций и другую информацию. Таким образом, каждый объект растет на размер указателя - обычно 4 или 8 байтов.

Обращаясь к вашему первоначальному наблюдению: C++ имеет больше функций, не являющихся членами (обычно в пространстве имен std), но пространство имен лучше всего подходит для этого класса, чем класс. Действительно, пространства имен являются фактически логическими интерфейсами для «статических» функций и данных, которые могут охватывать многие «физические» файлы заголовков. Почему логический API программы должен быть скомпрометирован соображениями, связанными с физическими файлами, и их последствиями для создания времени, запуск файла-модификации-timestamp, создание инструментов и т. Д.? В тривиальных случаях, когда пространство имен находится в одном заголовке, C++ может использовать класс или структуру для охвата одних и тех же объявлений, но это менее удобно, поскольку это предотвращает использование псевдонимов пространств имен, пространств имен using и поиск Koenig для неявного поиска пространств имен, соответствующих функции пространства имен аргументов - форсирование очень явного префикса в каждой точке использования. Он также дает ложное впечатление, что пользователь предназначен для создания объекта из содержимого.

Смежные вопросы