Что может быть причиной для того, чтобы сделать некоторые специфичные для класса функциональные возможности отдельной функцией вместо функции-члена? - PullRequest
1 голос
/ 31 августа 2010

При просмотре довольно старого кода я нашел странное дизайнерское решение:

// irrelevant stuff removed
class Class {
public:
   int GetStage() const { return stage; }
   void SetStage( int value ) { stage = value; }
private:
   int stage;
};

void ProgressStage( Class* object )
{
    int stage = object->GetStage();
    assert( stage < MaxStage );
    stage++;
    object->SetStage( stage );
}

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

void Class::ProgressStage()
{
    //directly access member variables
    assert( stage < MaxStage );
    ++stage;
}

В чем может быть причина предпочтения первого дизайна второму?

Ответы [ 7 ]

4 голосов
/ 31 августа 2010

В C ++ свободные функции являются предпочтительным способом ведения дел. Класс должен представлять минимальный интерфейс для своей работы. Языковые функции, такие как зависимый от аргумента поиск, работают для связывания свободных функций с классами операндов. Такие функции добавляют «сахар» в интерфейс.

Вот статья Херба Саттера, известного члена комитета по стандартам:

http://www.gotw.ca/publications/mill02.htm

Редактировать: Теперь, когда я остановился и прочитал ваш код, это выглядит чрезмерно. Единственное «задание», которое, по-видимому, выполняет класс, - это обеспечение stage < MaxStage, то есть сохранение инварианта в своем состоянии.

Предположим, что этапы не могут быть пропущены или изменены, возможно, SetStage следует исключить и AdvanceStage следует переместить в класс. В любом случае, похоже, что SetStage должно содержать это утверждение, а не функцию free.

2 голосов
/ 31 августа 2010

Причина в том, что это лучшее решение.

Почему бы вы бы предпочли, чтобы функция была методом-членом?Чтобы он мог получить доступ ко всем закрытым членам, которые ему не нужны?

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

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

это идиоматическое решение в C ++, как описано здесь или здесь .

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

В операторе . нет ничего особенно "объектно-ориентированного".Его использование не обязательно делает ваш код «более ООП» (или «лучше», если на то пошло).

1 голос
/ 31 августа 2010

Я бы просто использовал:

class Class { 

public:
    bounded<unsigned, 0, MaxStage> stage;
};

используя ограниченный шаблон, который я опубликовал в предыдущем ответе . Это предполагает / требует, чтобы MaxStage было константой. Если это не так, вы можете использовать вариант той же идеи, который вместо этого передает границы ctor (также полезно для ограниченных типов с плавающей запятой).

1 голос
/ 31 августа 2010

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

0 голосов
/ 31 августа 2010

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

Лично я с вами согласен - это звучит намного более естественно и последовательно как участник.

Если бы Class был структурой вместо этого, я бы сказал, что, возможно, он будет экспортирован в C-вызываемый интерфейс, но это невозможно (AFAIK) для класса (если вы не используете указатель void).

0 голосов
/ 31 августа 2010

Этот класс мне кажется объектом данных (DAO), так как бизнес-логика не включена.Вероятно, они хотели отделить бизнес-логику от уровня сущности.Но я тогда не знаю, почему они не поместили бизнес-логику в класс менеджера или что-то подобное.

0 голосов
/ 31 августа 2010

Нет веских причин предпочесть функцию.C ++ не является чисто объектно-ориентированным, поскольку позволяет писать функции вместо методов.

Кроме того, по какой причине вы используете временную переменную для сцены?Это для Assert?Я бы изменил это на:

assert(stage+1 <= MaxStage);
++stage;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...