LINUX.ORG.RU

Есть ли какой нибуть смысл делать функцию методом класса если она не использует ни одного другого члена или метода класса?

 , ,


0

1

тоесть прямее будет реализован класс A или класс B

class A {
    int x;
    int f1() { return 5; }
    void f2() { x = f1(); }
}
int f1() { return 5; }

class B {
    int x;
    void f2() { x = f1(); }
}
★★★★★

Прямее будет реализовать оба класса. В одном будет статический метод f1() , а в другом - остальное.

Slavaz ★★★★★
()

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

kravich ★★★★
()
Ответ на: комментарий от Slavaz

Прямее будет реализовать оба класса. В одном будет статический метод f1() , а в другом - остальное.

Это называется Java головного мозга, для разграничения видимости имён в С++ есть пространства имён.

Begemoth ★★★★★
()

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

Функция, конечно, должна быть статичной.

unsigned ★★★★
()

Есть ли какой нибуть смысл делать функцию методом класса если она не использует ни одного другого члена или метода класса?

1. Когда функция по смыслу тесно связана именно с этим классом. Иначе говоря, если её использование отдельно от класса было бы явной бессмыслицей.
2. Когда функция является деталью реализации этого класса. Просто чтобы не засирать пространство имён.

нибуть

Розенталь тебя ненавидит.

Manhunt ★★★★★
()
Ответ на: комментарий от cvv

а что даст такой подход? смысл заворачивать f1() как статический метод класса?

Если у вас есть десяток f1() - f10() сходной тематики, то обернуть их можно в класс или в именованный неймспейс.

andreyu ★★★★★
()
Ответ на: комментарий от cvv

Если функция логически привязана к классу - полагаю, да.

unsigned ★★★★
()
Ответ на: комментарий от cvv

является идеальным решением?

Поскольку int f1() в данном случае private и ей не нужен доступ к методам и членам класса B, то ее вообще можно вынести в файл определения, что бы не засирать хидер.
И сделать ее статиком.

andreyu ★★★★★
()
Ответ на: комментарий от Manhunt

1. Когда функция по смыслу тесно связана именно с этим классом. Иначе говоря, если её использование отдельно от класса было бы явной бессмыслицей.
2. Когда функция является деталью реализации этого класса. Просто чтобы не засирать пространство имён.

Я бы в таком случае определил функцию в .cpp либо использовал анонимный namespace, как раз чтобы не захламлять определение класса.

gv
()
Ответ на: комментарий от andreyu

И сделать ее статиком.

Эт не обязательно. Безымянного неймспейса хватит.

// inside some .cpp file:

static void foo();    // old "C" way of having internal linkage

// C++ way:
namespace
{
   void this_function_has_internal_linkage()
   {
      // ...
   }
}
slackwarrior ★★★★★
()
Ответ на: комментарий от andreyu

Поскольку int f1() в данном случае private и ей не нужен доступ к методам и членам класса B, то ее вообще можно вынести в файл определения, что бы не засирать хидер.

В 80% случаев в хидере лучше оставить только публичные методы. Всё остальное - в pimpl. Работает чуть медленнее, чуть тяжелее модифицировать публичные интерфейсы, но зато ковырять реализацию — сплошное удовольствие.

Manhunt ★★★★★
()
Ответ на: комментарий от gv

Я бы в таком случае определил функцию в .cpp либо использовал анонимный namespace, как раз чтобы не захламлять определение класса.

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

То, что в C++ определение публичного интерфейса обычно оказывается перемешано с фрагментами его реализации — это изъян языка.

Полностью отделить реализацию и поместить её в .cpp можно либо с помощью pimpl, либо с помощью фабрик и pure virtual интерфейсов...

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 4)

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

no-such-file ★★★★★
()
Ответ на: комментарий от Manhunt

Ну так а мы говорим как раз про best practice для C++, т.е. его особенности - это данность.

Если ситуация такая (не важно, используется pimpl или нет):

class Worker {
public:
  void doit();

private:
  void helper1();
  void helper2(string);
  bool helper3(const foo &);
  ...
};

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

gv
()
Ответ на: комментарий от gv

когда читаешь код, хрен разберешь, какие данные класса какой helper использукомпозицииет

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

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

Простота написания и простота понимания очень часто противоречат друг другу. Груды хелперов в анонимном неймспейсе — это скорее способ замести грязь под ковёр, чем средство декомпозиции. По-хорошему нужно постараться представить исходный класс в виде композиции самодостаточных (в том числе, слабо-связанных-друг-с-другом) узко-специализированных сущностей. Нередко эти сущности будут реализованы в отдельных .cpp файлах.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

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

О том и речь.

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

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

Сейчас я стараюсь писать плоский код, т.е. по возможности средствами ООП заниматься декомпозицией только в «горизонтальном» направлении. А разные слои/уровни выносить в отдельные процессы либо библиотеки. Т.е. там, где нужна серьезная декомпозиция — решать вопрос более кардинально, а там, где нет — обходится по-возможности без введения вспомогательных классов.

Это конечно не универсальное правило, по факту всегда компромисс.

gv
()
Ответ на: комментарий от Manhunt

Груды хелперов в анонимном неймспейсе — это скорее способ замести грязь под ковёр.

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

gv
()
Ответ на: комментарий от slackwarrior

Эт не обязательно. Безымянного неймспейса хватит.

Одно не отменяет другого. По ситуации или предпочтениям.

andreyu ★★★★★
()
Ответ на: комментарий от Manhunt

В 80% случаев в хидере лучше оставить только публичные методы.

Особенно, если описывается некий интрефейс (не UI, естественно).

Всё остальное - в pimpl. Работает чуть медленнее, чуть тяжелее модифицировать публичные интерфейсы, но зато ковырять реализацию — сплошное удовольствие.

Да.

andreyu ★★★★★
()

Уже второй вопрос, говорящий о полном непонимании ООП. Читай книжки.

slovazap ★★★★★
()
Ответ на: комментарий от gv

Только тогда куча utility-классов — расфасовывание грязи по аккурятным пакетикам, а иногда еще выстраивание из них красивой пирамидки.

Грязь вынули из-под ковра, расфасовали по пакетикам, пакетики надписали и выставили на стол. Хаоса (в том, что раньше лежало под ковром) убавилось, а отношение к расфасованному коду стало более внимательным: в плане повторного использования, юнит-тестирования, ревью и прочих ритуалов.

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

Согласен. Если удариться в крайность, то стол будет завален грудой пакетиков, и в ней уже никто никогда не разберется.

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 2)
int f1() { return 5; }

А нафея заворачивать фактически константу в функцию? Чем не нравится

const int f1 = 5;
нопремер?

one_more_hokum ★★★
()

Нет. Для этого есть namespace.

invy ★★★★★
()
Ответ на: комментарий от one_more_hokum

Это была иллюстрация что функция не пользует члены класа

cvv ★★★★★
() автор топика

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

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

Собсно разница между функциями-членами namespace и static функциями-членами класса заключается в ODR: мембер в класс добавить нельзя никак. Они все должны быть перечислены в момент определения класса, а в namespaceмембер добавить можно всегда.

Remington
()
Ответ на: комментарий от cvv

является идеальным решением?

ИМХО да, если f1() _действительно_ никаких данных класса не использует в принципе.

drBatty ★★
()
Ответ на: комментарий от drBatty

Я бы добавил "... и если есть уверенность что она никогда не будет работать с объектами класса и с их производными"

Remington
()
Ответ на: комментарий от Remington

и если есть уверенность что она никогда не будет работать с объектами класса и с их производными»

согласен.

drBatty ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.