C ++ Getters-Setters в файле реализации - PullRequest
7 голосов
/ 04 августа 2011

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

class myClass{
    public:
        double getVar1();
        void setVar1(double newVar1);
        void copyVar1(myClass* dat);

    private:
        double var1;
};

. В моем файле .cc реализации при реализации метода copyVar1 я должен сделать

void myClass::copyVar1(myClass* dat){
   var1 = dat->var1;
}

или

void myClass::copyVar1(myClass* dat){
   var1 = dat->getVar1();
}

где во втором случае вместо этого я использую метод получения.Оба работают правильно в Visual C ++, но я хотел бы знать, что лучше использовать на практике.

Спасибо за ваши комментарии!

Ответы [ 8 ]

4 голосов
/ 04 августа 2011

Лучшие практики? Перегрузите оператор присваивания вместо написания метода.

myClass & myClass::operator=(const myClass & dat)
{
   var1 = dat.var1; // or dat.getVar1()
   return *this;
}

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

Итак, большое «зависит».

2 голосов
/ 04 августа 2011

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

Ваше решение будет основано на том, есть ли в методе getter код, который делает нечто большее, чем просто возвращение переменной, и , если вы хотите, чтобы этот код запускался, когда copyVar1 называется, Если вы не знаете, мой совет будет по-прежнему использовать метод получения, если вы когда-нибудь решите изменить код в нем в будущем. Хотя теперь он работает нормально, просто получая прямой доступ к нему, и у вас может быть микроскопически лучшая производительность, будет намного легче обнаружить ошибку вызова геттера, если вы не должны этого не вызывать, когда вам нужно. И компилятор, вероятно, в конечном итоге оптимизирует настолько, что вы даже не почувствуете разницу. : D

1 голос
/ 04 августа 2011

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

0 голосов
/ 04 августа 2011

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

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

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

void myClass::copyVar1(myClass * dat)
{
    scoped_lock lock(mutex);
    var1 = dat->getVar1();
}

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

void myClass::copyVar1(myClass * dat)
{
    scoped_lock lock(mutex);
    scoped_lock lock2(dat->mutex)
    var1 = dat->var1;
}

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

Точно так же, если переменная начала храниться в базе данных, вам также придется с этим справиться. Или, если переменная теперь хранится в двух разных переменных и создается при ее извлечении, вы можете увидеть, как сложность возрастет.

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

0 голосов
/ 04 августа 2011

Как вы говорите, оба работают правильно и совершенно законно.

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

Другими словами, метод получения в основном отвечает требованию не раскрывать внешнему миру детали реализации;скажем, вы могли бы однажды решить, что вместо того, чтобы хранить var1 как двойное число, вы рассчитываете это.Таким образом, средство доступа предоставляет вам такую ​​свободу: в некоторой степени вы можете изменить реализацию, не затрагивая другие классы (т. Е. Уменьшая зависимости).

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

0 голосов
/ 04 августа 2011

Здесь нет правильного или неправильного способа сделать это.

Однако вы предполагаете, что getVar1 () возвращает значение или var1. Если вы решите изменить способ хранения значения var1, вам нужно пройти весь код и обновить его. Использование метода установки / получения сокращает это до пары методов. В этом случае вы должны использовать третий вариант:

void myClass::copyVar1(myClass* dat){
   setVar1 (dat->getVar1());
}

и затем вы полностью удаляете зависимость от var1, вы можете изменить var1 на что-то другое, и copyVar1 все равно будет работать.

0 голосов
/ 04 августа 2011

Вы пытаетесь написать конструктор копирования?Зачем вам нужно copyVar1, когда у вас есть setVar1?Если вы пытаетесь написать конструктор копирования, лучше не использовать геттер.

myclass(const myclass& other)
{
var1 = other.var1;
}

Если у вас есть и getter, и setter, почему бы не сделать var1 общедоступным?

0 голосов
/ 04 августа 2011

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

...