Всегда создавать классы на С++?

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

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

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

Ответы

Ответ 1

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

class HelperFunctions
{
public:
    static void DoSomethingUseful() { /* useful bits */ }
    // yata yata
private:
    HelperFunctions(); // private default constructor
    HelperFunctions(const HelperFunctions&); // private copy constructor
};

Тогда вы можете сделать что-то вроде этого:

HelperFunctions::DoSomethingUseful();

Но вы не могли бы сделать что-то вроде этого:

HelperFunctions myHelperFunction; // private constructor = compile error

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

namespace HelperFunctions
{
   void DoSomethingUseful() { /* useful bits */ }
   // yata yata
}

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

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

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

Изменить: Почему так серьезно?

Я не предполагал, что OP должен или не должен делать. Казалось, что они были новыми для С++, исходящими из Java-мира, где все это метод, а все "функции" - это члены класса. На это повлиял мой ответ: показать, как сначала вы можете создать что-то на С++, аналогично тому, что у вас есть на Java, а во-вторых, как вы можете делать и другие вещи, и почему это так.

Как утверждали другие, он считает, что хорошая практика предпочитает не-членские функции, отличные от друга, по возможности по разным причинам. Я согласен, если вам не нужен объект с состоянием, чем вы, вероятно, не должны его проектировать. Однако я не уверен, искал ли OP философское обсуждение лучших практик в области проектирования и реализации или просто любопытство для эквивалентного С++.

Я надеялся, что моя последняя строка, шутящая о том, чтобы выстрелить себе в ногу, была достаточной, чтобы подчеркнуть, что "просто потому, что вы можете, не означает, что вам следует", но, возможно, не с этой толпой.

Ответ 2

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

Ответ 3

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

Мое первое предпочтение

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

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

Файловый ввод-вывод является примером того, что имеет состояние. Вы открываете файл, записываете в него некоторые данные, которые перемещаются вперед по указателю записи и в конечном итоге закрывают его, что является хорошим примером того, где вы хотите класс.

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

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

(2) Необходимо, потому что безопасное обновление состояния является необходимой частью жизни, и если вы не можете скрывать данные или инкапсуляцию данных, вы теряете уверенность в том, что состояние поддерживается правильно и безопасно.

Ответ 4

Вы можете определить пространство имен вместо класса.

namespace mycode
{
    //Code for the library here
    void myfunction()
    {
         //function definition
    }
}

тогда, когда вам нужно его использовать, вы можете либо предисловие, либо использование пространства имен

mycode::myfunction()

или

using mycode;

myfunction();

Ответ 5

Собственно, если код не принадлежит классу, вы не должны помещать его в класс на С++. То есть, следует использовать функции не-t20 > non-member для функций-членов и friend. Причина в том, что вытаскивание метода из класса приводит к лучшей инкапсуляции.

Но не верьте мне на слово, см. "Эффективный С++" Скотта Мейерса. Item # 23: Предпочитайте функции, не являющиеся членами-членами, для функций-членов.

Ответ 6

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

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

Что касается общего руководства, я не думаю, что имеет значение, если у вас есть (нестатические) функции или статические методы в качестве интерфейса вашей библиотеки, это в основном вопрос синтаксиса: call f() или call obj::f(). Вы также можете использовать namespaces для инкапсуляции. В этом случае синтаксис: ns::f() для функции и ns::obj::f() для статического метода.

РЕДАКТИРОВАТЬ: Хорошо, но, хотя в ключевом слове static возникла путаница, получается, что это скорее спорный ответ, чем я бы хотел. Я лично предпочитаю термин метод для функций-членов (который также является тем же самым лексиконом, который используется в фактическом вопросе). И когда я сказал, что статические методы могут вызывать частные методы, я имел в виду видимость (контроль доступа a.k.a.).