Закрытые функции C ++: передавать переменную-член класса по параметру функции или нет - PullRequest
7 голосов
/ 22 марта 2012

Вот вопрос, который снова и снова возникает в реализации класса C ++. Мне интересно, что люди думают здесь. Какой код вы предпочитаете и почему?

class A
{
public:
    /* Constructors, Destructors, Public interface functions, etc. */ 
    void publicCall(void);

private:
    void f(void);

    CMyClass m_Member1;
};

с

void A::publicCall(void)
{
    f();
}

void A::f(void)
{
    // do some stuff populating  m_Member1
}

Или альтернатива:

class A
{
public:
    /* Constructors, Destructors, Public interface functions, etc. */ 
    void publicCall(void);

private:
    void f(CMyClass &x);

    CMyClass m_Member1;
};

с

void A::publicCall(void)
{
    f(m_Member1);
}

void A::f(CMyClass &x)
{
    // do some stuff to populate x, 
    // locally masking the fact that it's really m_Member1
}

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

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

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

Ответы [ 5 ]

3 голосов
/ 22 марта 2012

Поскольку вы запрашиваете мнения, если отдельная функция f(CMyClass&) имеет смысл и является выполнимой, то я также предпочел бы эту опцию. Я бы выбрал первый случай, если операция, выполняемая f, имеет смысл только в контексте класса A, если CMyClass имеет смысл только в контексте A или если она зависит от других атрибутов A. Я думаю, что нужно решить в зависимости от проблемы.

2 голосов
/ 22 марта 2012

Как всегда, это зависит. Каждый сценарий отличается.

В конкретном примере, который вы привели - сначала я исключил бы вашу альтернативу (void A::f(CMyClass &x)) главным образом потому, что она "пахнет" плохо (как выразился Мартин Фаулер). Это частная функция, и если вам не нужно использовать ее сейчас для других случаев, заставьте ее использовать член. Вы всегда можете выполнить рефакторинг, если возникнет такая необходимость.

Представьте себе, что случилось бы, если бы f имел 2 параметра. 3 параметра. 10. Имеет ли смысл отправлять их каждый раз? Не лучше ли иметь эти параметры-члены?

А что, если f должен был отправить некоторые из этих аргументов другим методам A? Разве не имеет смысла использовать членов для этого?

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

1 голос
/ 22 марта 2012

Я бы основал ответ на контексте.Если сейчас или когда-нибудь может быть несколько экземпляров переменных-членов, с которыми f может работать, тогда обязательно передайте его / их в качестве параметров.Однако, если f работает с определенными элементами состояния экземпляра A, я бы ничего не передал ему.Есть много случаев, когда в A. всегда будет только один foo. В этот момент глупо делать foo параметром для f.И чуть менее эффективно, если только f не встроен, поскольку передается не только указатель this, но и адрес foo, который является дополнительной копией в стек.

1 голос
/ 22 марта 2012

Разве не f во втором примере лучше статической функции A или глобальной функции или, может быть, функции-члена CMyClass?

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

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

1 голос
/ 22 марта 2012

Спросите себя: имеет ли это какое-либо значение сейчас или может иметь какое-либо значение в обозримом будущем, чтобы вызвать f() с объектом, отличным от m_Member1?

Если ответ:

  • Нет . Сделайте f() без параметров, так как m_Member1 является неотъемлемой частью A.
  • Да . Сделайте f(CMyClass &). Даже если сейчас вы используете только m_Member1, это не является внутренним свойством классов, с которыми вы работаете.
  • Может . Ну ... я бы сказал, что идти без параметров f(). Всегда есть возможность изменить свое мнение (на самом деле это изменение довольно тривиально).

Также обратите внимание, что функция f() может вызывать другую функцию g(CMyClass &), но не наоборот. Таким образом, в зависимости от того, что делает f(), это может ограничить ваши возможности.

...