Open klappdev opened 2 years ago
tl;dr: пример и аргументация кажутся неудачными, идею критике подвергать пока не буду.
При работе с классами, хорошей практикой, является объявление полей закрытыми. Возьмём для примера класс QPoint с фреймворка Qt.
Спорный переход: QPoint больше похож на структуру данных (внешний функционал), которую Qt почему-то реализовал как класс. Получился "квазикласс" в терминах этой статьи: http://www.idinews.com/quasiClass.pdf
Концепция свойств(геттеров, сеттеров) существует во многих языках, таких например как Swift, Kotlin, C# и д.р., на уровне языка.
Заметим, что во многих не менее замечательных языках концепция свойств годами отсутствует.
Концепция свойств(геттеров, сеттеров) как раз позволяет писать меньше кода, и при этом код остается таким же читаемым.
Если полей в структуре немного, то и кода для автоматических геттеров/сеттеров нужно немного, особенно с наличием auto
и decltype
.
Если полей в структуре много... то с ней чего-то не то.
class QPoint {
public:
// construct, dectructor, other
private:
int x {
set(int value) {
std::cout << "invoke setter - x" << std::endl;
this->x = value;
};
get() const {
std::cout << "invoke getter - x" << std::endl;
return x;
};
};
int y { set; get; };
};
В этом примере следующий шаг, который хочется сделать — применить этот геттер/сеттер к y
. В этот момент естественно ввести класс QCoordinate
, в котором определить operator=
и operator int()
.
class QPoint {
public:
// construct, dectructor, other
private:
int x { set; get; };
int y { set; get; };
};
Много вопросов, как это будет сочетаться с конструкциями, специфичными для C++.
Раз:
QPoint p;
std::vector<int*> pointers;
pointers.push_back(&p.x); // что это?
Два:
// что будет делать такой код?
auto pointer_to_member = &QPoint::x;
p.*pointer_to_member = 3;
Три:
QPoint::QPoint(int a, int b) : x(a), y(b) { } // вызывать ли сеттер?
Старые предложения об автоматических геттерах/сеттерах и более общем случае неявных функций, все не позднее 2005 года:
В последнем предложении содержится много критики к решениям уровня языка
Геттеры/сеттеры на уровне языка работают как буто простые методы. Поэтому не должно конфликтовать с другими частями языка. В С++23 добавили deducing this. Что является тоже пересмотром методов в частности. И позволяет меньше писать шаблонного кода. Поэтому почему не пересмотреть и в сторону свойств.
Тривиальные геттеры и сеттеры это ошибка проектирования и бесполезный код. В джаву С++ не нужно превращать Сеттер должен делать что-то осмысленное и называться не SetX, например vector::resize/reserve, это вообще говоря в ваших терминах сеттеры, но называются они осмысленно и делают логичные для инкапсуляции логики вещи P.S. в расте есть vec::set_len просто ору
Вообще геттеры и сетеры очень удобны если нужно автоматически оповещать об изменении в данных. И на C++ довольно не удобно получать указатель на this класса, который содержит подобные геттеры и сеттеры.
При работе с классами, хорошей практикой, является объявление полей закрытыми. Для чтения значения полей из вне, в классе объявляют геттеры. А для записи объявляют сеттеры.
Возьмём для примера класс QPoint с фреймворка Qt.
https://code.woboq.org/qt5/qtbase/src/corelib/tools/qpoint.h.html
При этом в большинстве случаев, геттеры и сеттеры очень простые. И не хочется писать руками.
Для того, чтобы каждый раз не писать геттеры, сеттеры, ничего не мешает реализовать оберточки.
https://github.com/klappdev/firearrow/blob/master/app/src/main/cpp/util/property/Property.hpp https://github.com/klappdev/firearrow/blob/master/app/src/main/cpp/util/property/Getter.hpp https://github.com/klappdev/firearrow/blob/master/app/src/main/cpp/util/property/Setter.hpp
Концепция свойств(геттеров, сеттеров) существует во многих языках, таких например как Swift, Kotlin, C# и д.р., на уровне языка. Хочется что б в С++ завезли такую возможность на уровне языка. Например, это могло выглядить как в С#.
Предлагаю добавить два контекстных ключевых слова - set, get. Которые были бы ключевыми словами, только при объявлении поля класса. По аналогии с обычными методам, можно бы объявлять с разными квалификаторами - &, &&, const, volatile, noexcept. В случае если нужно не тривиальный геттер, сеттер, то код мог бы выглядеть следующим образом.
Под капотом, компилятор генерировал те самые методы геттеры, сеттеры. Современный С++ вносит много новых фич, которые позволяет писать меньше шаблонного кода. Концепция свойств(геттеров, сеттеров) как раз позволяет писать меньше кода, и при этом код остается таким же читаемым. Очень хочется видеть в С++.
Полезные ссылки: