"Перенаправить" функции-члены класса? - PullRequest
1 голос
/ 28 февраля 2012

По сути, я сегодня написал много кода, как показано ниже:

#define VAL_1 0
#define VAL_2 1

class A {

public:
  void memberA();
  void memberB();

  ...

  void write(uin32_t address);

}

void
A::
memberA() {

  this->write(VAL_1);

}

void
A::
memberB() {

  this->write(VAL_2);

}

...

Так что, в принципе, у меня есть "красивые" имена memberA, memberB для какой-то задачи, которая действительно вызывает только одну и ту же функцию write с другим аргументом. Значения VAL_0 и VAL_1 не обязательно известны для кодирования с использованием моего класса. Ни детали реализации не лежат в основе memberA или memberB, хотя write может быть опубликован в какой-то момент.

По сути, теперь я повторяю одну и ту же строку кода this->write(...) снова и снова. Я ищу решение, которое обходит этот шаг и немедленно вызывает соответствующую запись. Тип передачи аргументов функции, похожий на конструктор C ++ из базового класса, возможно с соответствующими аргументами:

#define VAL_1 0
#define VAL_2 1

class A {

public:
  bool memberA() : write(VAL_1);
  bool memberB() : write(VAL_2);

  ...

  bool write(uin32_t address);

}

Мне интересно, может ли быть что-то в Boost.Bind или какое-нибудь умное шаблонное кодирование, которое позволяет мне достигать такого рода или чего-то такого?

Спасибо

Frob

Ответы [ 2 ]

4 голосов
/ 28 февраля 2012

Если вы сделаете свои функции memberX встроенными в определение класса, и если вы избежите избыточной ссылки this, то у вас не будет слишком много лишних слов для записи:

Желаемый (неверный)) синтаксис:

bool memberA() : write(VAL_1);

Фактический (правильный) синтаксис:

bool memberA() { return write(VAL_1); }

Если вы хотите свести к минимуму повторяющийся код, вы можете использовать препроцессор:

#define F(l, n) bool l() { return write(n); }
 F(memberA, VAL_1)
 F(memberB, VAL_2)
#undef F

Кроме того, вы можете использовать оператор вставки токена препроцессора ##:

#define F(l, n) bool member##l() { return write(VAL_##n); }
 F(A, 1)
 F(B, 2)
#undef F
2 голосов
/ 28 февраля 2012

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

...как насчет просто:

class A {
public:
    enum Value {val1, val2, val3, val4, etc};
    bool write(Value val);
};

Хорошо, что вы пытаетесь установить более простой синтаксис, но вы также должны избегать опасности монолитизма.Я уверен, что монолитные классы - это одна из самых распространенных ошибок в объектно-ориентированном дизайне.Саттер подробно расскажет об этом в C++ Coding Standards и на гтв: http://www.gotw.ca/gotw/084.htm.

Если у вас есть класс с 100 функциями-членами, у вас, вероятно, их около 80.

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

Попытка слишком сильно избежать синтаксической избыточности обычно является ошибкой.К сожалению, в некоторых случаях C ++ требует более продолжительного синтаксиса (становится намного лучше с C ++ 11).То, что вы должны попытаться оптимизировать, это логическая избыточность .Здесь вызов метода записи с различными значениями не требует никакой логической избыточности, и синтаксические издержки едва ли превышают вызов различных функций для каждого значения, которое вы можете передать для записи.

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

Постарайтесь помнить об этом аспекте монолитизма как о приоритете.Вы могли бы даже пойти так далеко, чтобы вывести именованные константы из определения класса как не-члены, например так:

class A {
    bool write(uint32_t address);
};

// elsewhere
static const uint32_t address_val1 = ...;
static const uint32_t address_val2 = ...;
static const uint32_t address_val3 = ...;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...