Когда используются «статические функции»?

25

Хорошо, я узнал, что такое статическая функция, но я до сих пор не понимаю, почему они более полезны, чем закрытые функции-члены. Это может быть своего рода новым вопросом здесь, но почему бы не заменить вместо этого все закрытые функции-члены статическими функциями?

Темный тамплиер
источник
1
Разве это не должно быть "заменить все статические функции частными функциями-членами"? В настоящее время вы заявляете, что не видите смысла статических методов, и спрашиваете, почему мы не используем их больше.
5
Что такое "статическая функция"? В C ++ есть по крайней мере два значения (и в последний раз, когда я просматривал черновики C ++ 11, они удалили уведомление об устаревании staticдля ограничения функций областью действия файла.
Дэвид Торнли,
Вы имеете в виду «статическая функция» в смысле статической свободной функции на уровне файлов в C / C ++ или как «статическая функция / метод memenber»? Это огромная разница!
Ян Худек
@JanHudec: Я думаю, что с учетом присутствия private memberмы можем с уверенностью предположить, что OP спрашивает о концепции OO и не имеет ни малейшего представления о статической области видимости файла.
Матье М.
@MatthieuM .: На самом деле присутствие «частного члена» - это именно то, что заставляет меня поверить, что он имеет в виду статические функции в смысле C ++. Поскольку статические функции с файловой областью и функции закрытого члена - это две вещи, которые очень похожи в C ++, тогда как замена открытого статического члена закрытым нестатическим членом просто не имеет особого смысла. К сожалению, OP, похоже, не отвечает.
Ян Худек

Ответы:

25

Предполагая, что вы используете ООП , используйте статические функции, когда они не зависят ни от каких членов класса. Они все еще могут быть частными, но таким образом они оптимизируются, поскольку они не зависят ни от какого экземпляра связанного объекта.

Помимо вышесказанного, я считаю статические функции полезными, когда вы не хотите создавать экземпляр объекта только для выполнения одной общедоступной функции над ним. Это в основном относится к вспомогательным классам, которые содержат публичные функции для выполнения некоторой повторяющейся и общей работы, но не требуют поддержания какого-либо состояния между вызовами.

Бернард
источник
Спасибо Бернард. Кстати, вы знаете, что значит для компилятора «привязать метод к классу»?
Темный тамплиер
@ Темный тамплиер: Не могу сказать, что я делаю. Это специфично для конкретного языка?
Бернард
У меня небольшая проблема с вашим определением «они не зависят ни от каких учеников». Статические функции-члены не могут получить доступ к любому нестатическому члену, однако они могут получить доступ к статическим членам. Статические члены являются членами класса.
13
@newprint: Вы правы, но это не то, что я сказал. Я сказал, когда они не зависят от учеников. Использование статических элементов хорошо, если они необходимы, но это не всегда так.
Бернард
8

Попытка более простого объяснения, чем выше (довольно хорошие).

Объект - это код + данные в обычном режиме. Статический метод используется, когда у вас есть только часть кода, с которой нужно иметь дело (данные / состояние не поддерживаются (за исключением элементов статических данных)).

Brian Knoblauch
источник
5

Потому что они не требуют экземпляра и могут быть публичными. Скажем, вам нужна функция, чтобы получить наибольший общий знаменатель (GCD; очень полезно для классов дроби; да, это всего лишь простой пример). Нет смысла создавать класс объектов, единственной целью которых является то, что у вас может быть thisуказатель, в котором вы не нуждаетесь и не используете его gcd. Таким образом, вы используете статический метод для него, в идеале для класса, который фактически использует GCD (например, в классе дроби).

Конечно, если есть только статические методы, вы неправильно выполняете ООП и должны либо перейти к выполнению ООП, либо использовать язык, более подходящий для вашей парадигмы.

user7043
источник
Не лучше ли в вашем примере использовать бесплатную функцию?
Ela782
2
@ Ela782 Если у языка есть свободные функции, да.
Хорошо, спасибо за заверение. Я только изучил эту лучшую практику недавно. Тем не менее, в данный момент у меня возникают проблемы с пониманием того, может ли публичная статическая функция-член действительно быть полезной, скажем, на языке, подобном C ++. Вариант использования для обоих случаев - когда функция не зависит или не требуется экземпляр класса, а затем рекомендуются свободные функции. Может быть, это должен быть новый вопрос.
Ela782
1
@ Ela782 Да, это может быть хороший вопрос. Два быстрых момента: в частности, в C ++ статические члены полезны для шаблонного метапрограммирования, поскольку вы можете передавать тип в качестве параметра шаблона, но не пространство имен. В целом, статические функции могут использоваться, чтобы указать, что функция действительно тесно принадлежит некоторому классу, а не просто принадлежит в пространстве имен (думаю, stuff::Thing::Load(...)против stuff::LoadThing()).
2

Я использую их как вспомогательные функции для общих задач, например:

  • Преобразование градусов в радианы (и наоборот);
  • Хеширование строки;
  • Преобразование из перечисления во что-то еще (в этом проекте я работаю, они действуют как хеш-таблица);

Большинство моих файлов, которые группируют статические функции, имеют суффикс Helper, означающий, что именно это они и делают, помогают мне быстрее добраться куда-то.

Джордж Сильва
источник
2

Что касается статического метода:

Статические методы не требуют экземпляра класса и не могут неявно обращаться к данным (или этому, себе, Я и т. Д.) Такого экземпляра. [ 1 ]

Примеры использования статических методов:

  • Глобальные / вспомогательные методы
  • Получение результатов запроса из класса модели данных (вызов SP)

Просто используйте их там, где это уместно.

  1. Если вы обнаружите, что копируете одни и те же методы в несколько объектов, подумайте о том, чтобы сделать метод статичным, чтобы вы могли следовать DRY.
  2. Используйте статические методы, если вам не нужен экземпляр объекта (вы не работаете с переменными экземпляра объекта)

Если большая часть ваших данных находится за пределами объектов и они обрабатываются статическими методами, тогда ваш код не является объектно-ориентированным и может стать трудным в обслуживании.

кодировщик
источник
1

Статические и частные фактически являются ортогональными: метод может быть статическим или частным, или ни одного, или и тем, и другим.

Статический или нестатический (он же «методы экземпляра») указывает, работает ли метод на самом классе (статический) или на одном конкретном экземпляре (нестатический). В зависимости от языка вы можете вызывать статический метод через экземпляр, но вы никогда не сможете получить доступ к экземпляру через статический метод (что также подразумевает, что вы не можете вызывать какие-либо нестатические методы из статического метода просто потому, что у вас нет thisобъект). Используйте статические методы для реализации поведения, которое концептуально связано с классом, но не привязывается к одному конкретному экземпляру. Другой сценарий, в котором вы можете захотеть использовать статические методы, - это когда у вас есть функция, которая работает с двумя экземплярами класса, и ни один из операндов не заслуживает привилегированного статуса - например, если у вас есть классVectorи вы хотите реализовать сложение; Ваш метод сложения может быть вызван как a.Add(b), но, Vector.Add(a, b)вероятно, имеет больше смысла.

Приватный и публичный - о видимости метода. Доступ к закрытым методам возможен только из собственной области видимости класса, тогда как открытые методы доступны из любого места. Наиболее важным использованием для этого является инкапсуляция: делая общедоступными только те методы и свойства, которые абсолютно необходимы остальной части кода для взаимодействия с вашим классом, вы ограничиваете точки, в которых внешний код может создавать проблемы, и предотвращаете проблемы внутри. Ваш класс от кровотечения до остальной части проекта.

Итак, практическое правило:

  • сделать все функции-члены приватными, кроме тех, которые должны вызываться извне класса
  • сделать все методы экземплярами методов, если они не имеют смысла, даже если ни один экземпляр класса не существует
tdammers
источник
0

Я использую статические методы как в C ++, так и в C # для классов Utility, классов, у которых нет данных экземпляра, только один из способов связать коллекцию полезных связанных методов.

int count1 = DBUtil::GetCountOfSlackerEmployees();
int count2 = DBUtil::GetCountOfEmployedSlackers();
Крис О
источник
0

Предполагая, что вы говорите о C ++ (вы не сказали), и у вас есть правильные термины (то есть, они не означают функции / методы-члены):

Даже закрытая функция-член все еще должна быть объявлена ​​в заголовке, что означает, что она фактически становится частью API и ABI класса, даже если пользователь не может вызвать ее на самом деле. Если вы добавляете, модифицируете или удаляете закрытую функцию-член, вы принудительно перекомпилируете все зависимые классы (заголовок изменился, make не может знать лучше), а когда вы делаете это в библиотеке, вы должны учитывать совместимость приложения, используя Это.

С другой стороны, статические функции с файловой областью не получают общедоступный символ, поэтому вы можете добавлять, изменять или удалять их по своему усмотрению, и ничто, кроме одного модуля компиляции, не будет затронуто.

Ян Худек
источник
0

Как правило, вам нужен статический main, чтобы действовать как точка входа для вашей программы. Это может быть отчасти важно.

Уайетт Барнетт
источник
0

Статическая функция (и для этого термина есть разные значения) не требует состояния, которое сохраняется между вызовами. Если он концептуально тесно связан с тем, что делает класс, сделайте его функцией класса (как в случае с классом, а не объектом) или, если нет, сделайте его глобальной (или модульной, независимо от того) функцией. Он не принадлежит объекту, если он не нуждается в состоянии объекта.

Если вы все время передаете ему состояние, которое на самом деле не является функцией без сохранения состояния, вы просто создаете функцию с сохранением состояния с синтаксисом без сохранения состояния. В этом случае он, вероятно, принадлежит вызывающему объекту, или может быть указан рефакторинг для лучшего выравнивания состояния и поведения.

kylben
источник
0

"Почему бы просто не заменить все закрытые функции-члены статическими?"

... потому что закрытый член может получить доступ к данным экземпляра, в то же время позволяя ему происходить только из вызовов, выполняемых внутри других функций-членов. Статическая функция может быть закрытой, но она не сможет изменять или ссылаться на экземпляр класса, если экземпляр не передан в качестве параметра.

jheriko
источник
0

Забавно, что пока никто не смог дать хороший ответ. Я не уверен, что это тоже. Вы, вероятно, должны принять это как намек на то, что их следует использовать как можно меньше. Они все-таки процедурные, а не ООП.

Вот еще несколько примеров:

В Obj-C, где они называются методами класса, они обычно используются в качестве оболочек выделения, когда объект помещается в пул подсчета ссылок перед его возвратом.

Другой пример из Obj-C - это регистрация нового класса в коллекции классов. Допустим, у вас есть набор классов, каждый из которых обрабатывает один тип файла. Когда вы создаете новый класс для нового типа файла, вы можете зарегистрировать его в коллекции (глобальная переменная), используя статический метод в классе, который определяет тип файла.

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

Пер Йоханссон
источник
0

Допустим, вы хотите вычислить синус чего-то.

Без статики:

Math math = new Math()
double y = math.sin(x)

Со статическим:

double y = Math.sin(x)

Нет смысла делать sinнестатичные. Он не имеет состояния и просто обрабатывает ввод.

Статические функции не привязаны к конкретным объектам. Это «общие» функции, которые не зависят от внутреннего состояния объекта.

dagnelies
источник
Статические методы не «гарантированно не имеют состояния». Хотя это правда, что они не могут использовать данные экземпляра, они также имеют доступ к некоторому состоянию (а именно к статическим членам, как к классу, к которому принадлежит статический метод, так и к другому глобально видимому состоянию, такому как статические переменные других классов).
@delnan: правда ... ты прав. Позвольте мне исправить это прямо сейчас.
dagnelies
Без статического: x.sin(). Ваш ответ предполагает, что грех должен быть функцией «математики», тогда как он явно действует на двойник.
AjahnCharles
0

В некотором смысле здесь, но я хотел бы попытаться создать точное определение: статические функции - это функции, которые не ссылаются или не могут ссылаться на свойства / методы экземпляра содержащего класса.

В некоторых языках, таких как C #, могут быть статические поля или свойства в статических классах, поэтому не совсем правильно говорить, что они не используются для состояния; статическая функция может использовать статическое (глобальное) состояние.

По сути, это сводится к следующему: статические функции, как и все статические, полезны, когда имеет смысл, чтобы они всегда были доступны без зависимости от нестатических экземпляров.

Вспомогательные функции, такие как математические функции, являются частым примером, но есть и другие.

Если класс, который вы создаете, требует, чтобы данные были неизменными, возможно, имеет смысл создавать статические функции, которые принимают экземпляр и передают новый экземпляр, поскольку экземпляр не может (или не должен) изменяться. Строковые классы, например, могут иметь статические функции, которые принимают строку (или 2 или более) и возвращают новую строку.

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

боб
источник
0

Я хотел бы указать на другое использование статического f ().

http://www.parashift.com/c++-faq/named-ctor-idiom.html

Это сводится к следующему: staticфункции позволяют создавать «именованные конструкторы», т.е. вы называете статическую функцию подходящим и самодокументируемым именем, и эта статическая функция вызывает один из конструкторов (поскольку конструкторы имеют идентичные имена, и вы можете иметь их много, становится трудно их различать).

газетная бумага
источник