Почему C++11 строковые новые функции (stod, stof) не являются функциями-членами строкового класса?
Почему эти C++11 новые функции заголовка <string>
(stod
, stof
, stoull
) не является членом функции string
учебный класс?
Не более совместим с C++ для написания mystring.stod(...)
скорее, чем stod(mystring,...)
?
3 ответа
Это удивляет многих, но C++ не является объектно-ориентированным языком (в отличие от Java или C#).
C++ является мультипарадигмальным языком, и поэтому старается использовать лучший инструмент для работы, когда это возможно. В этом случае свободная функция - правильный инструмент.
Рекомендация: отдавать предпочтение функциям, не являющимся членами, а не функциям-членам (из Efficient C++, пункт 23)
Причина: функция-член или функция-друг имеет доступ к внутренним объектам класса, тогда как функция, не являющаяся членом-другом, не имеет доступа; поэтому использование функции, не являющейся членом-другом, увеличивает инкапсуляцию.
Исключение: когда функция-член или функция-друг обеспечивает значительное преимущество (например, производительность), тогда стоит задуматься, несмотря на дополнительную связь. Например, даже если std::find
работает очень хорошо, ассоциативные контейнеры, такие как std::set
обеспечить функцию-член std::set::find
который работает в O(log N) вместо O(N).
Основная причина в том, что они не принадлежат там. Они на самом деле не имеют ничего общего со строками. Остановись и подумай об этом. Пользовательские типы должны следовать тем же правилам, что и встроенные типы, поэтому каждый раз, когда вы определяете новый пользовательский тип, вам необходимо добавить функцию в std::string
, На самом деле это было бы возможно в C++: если std::string
имел шаблон функции-члена to
без общей реализации вы можете добавить специализацию для каждого типа и вызвать str.to<double>()
или же str.to<MyType>()
, Но действительно ли это то, что вы хотите. Для меня это не кажется чистым решением, когда все пишут новый класс, добавляя специализацию к std::string
, Помещение подобных вещей в строковый класс убивает его и на самом деле является противоположностью того, что ОО пытается достичь.
Если вы будете настаивать на чистой ОО, они должны быть членами double
, int
и т. д. (действительно, конструктор. Это то, что делает, например, Python.) C++ не настаивает на чистой ОО и не допускает базовые типы, такие как double
а также int
иметь членов или специальных конструкторов. Таким образом, свободные функции являются приемлемым решением и единственным чистым решением, возможным в контексте языка.
FWIW: преобразование в / из текстового представления - всегда деликатная проблема: если я делаю это в целевом типе, то я ввел зависимость от различных источников и приемников текста в целевом типе - и они могут варьироваться время. Если я делаю это в типе источника или приемника, я делаю их зависимыми от конвертируемого типа, что еще хуже. Решение C++ состоит в том, чтобы определить протокол (в std::streambuf
), где пользователь пишет новую бесплатную функцию (operator<<
а также operator>>
) для обработки преобразований и рассчитывает на разрешение перегрузки оператора, чтобы найти правильную функцию. Преимущество решения с бесплатной функцией заключается в том, что преобразования не являются частью ни типа данных (который не должен знать об источниках и приемниках), ни типа источника или приемника (который, таким образом, не должен знать о пользовательских типы данных). Это кажется лучшим решением для меня. И функции как stod
это просто удобные функции, которые облегчают написание одного частого использования.
На самом деле это некоторые служебные функции, и они не должны находиться внутри основного класса. Подобные служебные функции, такие как atoi, atof определены (но для char*) внутри stdlib.h, и они тоже являются автономными функциями.