Шаблоны для сеттеров и геттеров

Я не знаком с шаблонами, но мне интересно, можно ли их использовать для методов установки и получения. Например, в этой ситуации:

double exmlClass::getA(void) const
{
    return a_;
}



void exmlClass::setA(const double& a)
{
    a_ = a;
}



double exmlClass::getB(void) const
{
    return b_;
}

Как видите, методы почти такие же, за исключением того, что они относятся к другим частным переменным (a_, b_, c_). Есть ли более элегантный способ написать эти функции, или в таких ситуациях обычная практика - делать то же самое? И если это обычное дело для использования шаблонов, я был бы признателен за пример того, как вы могли бы использовать их в приведенном выше коде.

Еще один вопрос, который я хотел бы задать, - как правильно объявлять геттеры и сеттеры. Это хороший стиль программирования?

double getA(void) const;
void setA(const double& a);

double getB(void) const;
void setB(const double& b);

double getC(void) const;
void setC(const double& c);

Я имею в виду, должны ли геттеры всегда быть константными, а сеттеры принимать в качестве аргумента ссылку на объект, а не копировать его, что, вероятно, будет немного медленнее?


person Overpain    schedule 16.11.2010    source источник
comment
Если у вашего класса есть геттеры и сеттеры в таком количестве, что это проблема, я бы серьезно поставил под сомнение его дизайн .   -  person sbi    schedule 16.11.2010
comment
Кроме того, поскольку автор этой статьи не объясняет это (это лишь кратко упоминается в конце), я хочу выделить кое-что из статьи: 3. A lack of essential operators and other methods forces user programs to manipulate the object through the get and set accessor functions. Если ваши аксессоры являются операторами, это, по крайней мере, подразумевает, что автор статьи не не [обязательно] иметь такую ​​же жалобу.   -  person Brian Vandenberg    schedule 18.09.2015
comment
@Brian: Ну, у OP есть глупые геттеры и он спрашивает: Хороший ли стиль кодирования? Это очень надежный знак для новичка, сбивающегося с Пути Истины (™), вместо того, чтобы кого-то спрашивать об абстрагировании некоторых деталей реализации за геттерами.   -  person sbi    schedule 20.09.2015


Ответы (6)


Аро скептикам!

Boost.Fusion.Map это то, что вы ищете в качестве основы.

namespace result_of = boost::fusion::result_of;

class MyClass
{
public:
  struct AType {};
  struct BType {};
  struct CType {};

  template <typename Type>
  typename result_of::at< DataType, Type >::type &
  access(Type) { return boost::fusion::at<Type>(mData); }

  template <typename Type>
  typename result_of::at< DataType, Type >::type const &
  get(Type) const { return boost::fusion::at<Type>(mData); }

  template <typename Type>
  void set(Type, typename result_of::at< DataType, Type >::type const & v)
  {
    boost::fusion::at<Type>(mData) = v;
  }

private:
  typedef boost::fusion::map <
    std::pair<AType, int>,
    std::pair<BType, std::string>,
    std::pair<CType, float> > DataType;
  DataType mData;
};
person Matthieu M.    schedule 16.11.2010
comment
И тогда насколько легко специализировать один из этих методов для чего-то другого? (Потому что, если вы не собираетесь этого делать, у вас могут быть просто публичные данные.) - person aschepler; 16.11.2010
comment
@ Брайан Ванденберг: Извините, что ваше изменение было отклонено; Я поправил код. - person Matthieu M.; 18.09.2015

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

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

person DaVinci    schedule 16.11.2010
comment
проектируйте свои программы таким образом, чтобы не было необходимости в геттерах и сеттерах. Это противоречит правилу инкапсуляции объектно-ориентированного программирования ... - person peoro; 16.11.2010
comment
@peoro: Я не говорил, что он должен заменить аксессоры публичными членами. Ему следует просто оперировать своими данными, используя более значимые функции. Если существует так много средств доступа, которые ничего не делают, кроме возврата и установки внутренней переменной, очень вероятно, что классы используются очень похоже на структуры POD и, таким образом, только кажутся инкапсулированными. - person DaVinci; 16.11.2010
comment
@peoro: вы также можете взглянуть на ссылку sbis. - person DaVinci; 16.11.2010
comment
Хорошо, я понял ваш исходный пост, поскольку у него нет сеттеров и геттеров. Что такое sbis link? - person peoro; 16.11.2010
comment
Мне не хватало апострофа. sbi прокомментировал вопрос, разместив эту ссылку - person DaVinci; 16.11.2010
comment
+1, отличная ссылка и необходимость уменьшения геттеров / сеттеров вполне реальна. - person Moo-Juice; 16.11.2010
comment
@peoro: Не согласен. Предоставление члена общедоступных данных не нарушает инкапсуляцию не больше, чем предоставление общедоступных методов получения и установки, которые не делают ничего такого, что не делал бы член общедоступных данных. - person John Dibling; 16.11.2010
comment
@John: это так, он скрывает детали реализации, где хранится член данных. Вы можете использовать его в своем классе, а затем изменить его на другой класс, который будет составляться, или распределить его динамически ... все это невозможно с общедоступным членом данных. - person Matthieu M.; 16.11.2010
comment
@Matthieu: Я понимаю, что вы говорите, но я все еще не согласен с тем, что концептуально геттеры и сеттеры обеспечивают лучшую инкапсуляцию. Чтобы геттеры и сеттеры обеспечивали инкапсуляцию true, весь интерфейс должен быть абстрактным базовым классом. Остальные детали реализации просто висят там, чтобы все могли увидеть. - person John Dibling; 16.11.2010
comment
@MatthieuM. Затем используйте typedef. Создание непрозрачного типа исключительно потому, что вам может потребоваться изменить базовую реализацию, является формой ложной лени: c2.com / cgi / wiki? FalseLaziness - person Brian Vandenberg; 18.09.2015
comment
@BrianVandenberg: Понятия не имею, как ваш комментарий относится к этому пятилетнему разговору; Возможно, я забыл некоторые концепции, поэтому, если вы действительно надеетесь на ответ, боюсь, вы мне понадобитесь, чтобы экстраполировать то, о чем вы говорите. - person Matthieu M.; 18.09.2015
comment
@MatthieuM. Если я не прочитал то, что вы написали неправильно, я решил, что ваше последнее утверждение означает сначала сделать его непрозрачным, потому что в будущем вы можете захотеть изменить базовое поведение (например, назначив его динамически). Если я неправильно прочитал, не обращайте внимания на то, что я сказал. - person Brian Vandenberg; 19.09.2015
comment
@BrianVandenberg: Я говорил о сокрытии деталей реализации (как данные представлены внутри класса) и поэтому действительно рекомендовал сделать его непрозрачным, чтобы иметь возможность изменить способ представления указанных данных; обычно это не должно влиять на поведение или общедоступный API. Я бы не согласился, что это вообще ложная лень; с другой стороны, я рекомендую это только тогда, когда API используется публично, скрытие деталей реализации внутри не стоит головной боли. - person Matthieu M.; 19.09.2015

Я не вижу способа напрямую помочь вам с помощью шаблонов компактифицировать пары получателей и установщиков, если только вы не хотите обернуть членов внутри шаблонных классов доступа, таких как this. Другая возможность - использовать макрос #define для имитации свойств C # (если макросы не пугают вас или кого-то, кто читает ваш код).

Возвращают ли ваши геттеры (константные) ссылки на члены, возвращают указатели на члены или копируют их, зависит от нескольких факторов. Вы должны учитывать, дорого ли их копировать (с точки зрения производительности), есть ли семантически смысл копировать их, и возможно ли, чтобы информация, которую вы возвращаете, пережила класс, который вы ' повторно получить его от (если вы вернете указатель / ссылку на член, он останется висящим, как только вы удалите свой объект). И я бы использовал указатели вместо ссылок, если вы хотите допустить возможность того, что член будет нулевым.

Для геттеров я обычно возвращаю константные ссылки для чего угодно, кроме примитивов, которые я копирую. Для установщиков обычно используется параметр ссылки const.

person Nathan Pitman    schedule 16.11.2010
comment
Более простая оболочка: Boost.Fusion.Map. - person Matthieu M.; 16.11.2010

Технически возможно создать один шаблон функции exmlClass::set<PMF>, при котором exmlClass::set<&exmlClass::a_> будет действительным. Однако какой в ​​этом смысл?

person MSalters    schedule 16.11.2010

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

Макрос может это сделать, но это еще хуже.

Я обычно передаю / возвращаю объект класса по ссылке const, но простые встроенные типы, такие как double, только по значению:

public:
  const ClassType& getObj() const;
  void setObj(const ClassType& obj);
  double getNum() const;
  void setNum(double num);
person aschepler    schedule 16.11.2010

Теоретически вы могли:

template<typename A, typename B, typename C>
class Object
{
private:
    A _a;
    B _b;
    C _c;

public:
    Object()
    {
    };  // eo ctor

    // properties

    A getA() const {return(_a);}
    void setA(const A& _val) {_a = _val;}

    // etc for B & C
}; // eo class Object

    // .....

    Object<int, double, char> myObject;

Я вижу здесь несколько проблем. Во-первых, геттеры / сеттеры не должны быть «абстрактными» в том, что они передают пользователям вашего класса. Как вы собираетесь называть эти геттеры / сеттеры? получить() ? getAValue ()? Что это хотя бы значит?

Во-вторых, это определяет 3. Сколько вам нужно для ваших объектов? 1, 2, 4, 9?

В-третьих, геттеры / сеттеры должны называться в соответствии с их функцией:

getName()
getAddress()
getMovie()

Похоже, вы просто хотите сэкономить на вводе текста, а не оправданием для усложнения дизайна, imho.

Что касается вашей второй точки, верните ссылку на объекты (предпочтительно const), но не беспокойтесь о небольших, интегральных типах POD (Plain-Old-Data), таких как int, char, bool и т. Д.

person Moo-Juice    schedule 16.11.2010