Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Инициализация с помощью шаблонов


Домашняя страница www.devdoc.ru

DevDoc - это новые статьи по программированию каждую неделю.

Заходи и читай!

Домашняя страница Письмо автору Архив рассылки Публикация статьи

Выпуск №13

Здравствуйте, уважаемые подписчики.

Сегодня в выпуске:

  • Итоги конкурса
  • Задача на сообразительность
  • Статья: «Инициализация с помощью шаблонов»

Итоги конкурса

Завершился конкурс по программированию. Перед участниками была поставлена нетривиальная и достаточно трудная задача. Победителем стал Захаренков Алексей из города Долгопрудный. Он один прислал правильное решение. Алексей выпускник Московского Физико-Технического института (МФТИ), сейчас аспирант 1-го года Объединённого Института Высоких температур РАН.

Мои поздравления победителю! Приз будет выслан в ближайшие дни.

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

Задача на сообразительность.

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

Ваши ответы присылайте на мой адрес – ссылка вверху страницы. Самые интересные и оригинальные решения будут опубликованы.


Постоянная ссылка на статью (с картинками): http://www.devdoc.ru/index.php/content/view/template_init.htm

Автор: Кудинов Александр
Последняя модификация: 2007-03-19 21:22:48

Инициализация с помощью шаблонов

Введение

В практике программирования достаточно часто возникает задача, когда надо создать структуру и обнулить ее с помощью функции memset. Многие структуры Microsoft использует член структур cbSize в который надо записывать размер структуры.

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

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

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

Все примеры проверялись с помощью MS Visual Studio 2003 .NET.

Инициализация простых типов

Очень часто приходится писать классы, которые имеют несколько конструкторов. Для каждого из них приходится писать список инициализации всех членов. А что делать, когда большинство переменных класса должны иметь одни и те же значения, не зависимо от конструктора, который используется? Решение в лоб – использовать Copy/Past для списка инициализации. Это плохой способ. Во-первых, использование такого стиля написания программ – плохой тон. Надо всегда стараться использовать уже существующий код, вместо копирования. Этим мы и займемся. Во-вторых, при добавлении нового члена можно просто забыть прописать инициализацию во все конструкторы.

struct InitVar
{
 InitVar() : m_var(tVal) {}
 InitVar(const InitVar& rsrc) {m_var = rsrc.m_t;}
 
 operator T&() {return m_var;}
 operator T&() const {return m_var;}
 T* operator&() {return &m_var;}
 const T* operator&() const {return &m_var;}
 T& operator=(const T& t) {return (m_var = t);}
 
private:
 T m_var;
};

Для того чтобы объявить переменную с типом int, надо написать:

InitVar<int, 10> iTest;  //эквивалентно int iTest = 10;

Не имеет смысла объявлять так обычные переменные. Зато, если мы объявляем с помощью этого шаблона член класса – мы получаем выгоду.

class KWindow : public CWnd
{
 ...
InitVar<int, 10> m_iTest;  //эквивалентно int iTest = 10;
 ...
};

Вызов конструктора m_iTest и инициализация будет сделана перед выполнением тела конструктора KWindow. Это нам и требовалось! Теперь мы можем делать несколько конструкторов, и не заботится о том, чтобы выполнять одинаковую инициализацию в каждом из них.

Инициализация структур

Рассмотрим задачу первоначального обнуления структуры и как частный случай – запись в cbSize ее размера.

template <typename T>
struct SetZero : public T
{
 SetZero()
 {
  ZeroMemory(this, sizeof(T));
 }
};
 
template <typename T>
struct SetSize : public T
{
 SetSize()
 {
  this->cbSize = sizeof(T);
 }
};
 
template <typename T>
struct SetSizeClear : public T
{
 SetSizeClear()
 {
  ZeroMemory(this, sizeof(T));
  this->cbSize = sizeof(T);
 }
};

Эти три шаблона используются для обнуления, установки размера структуры и выполнения этих двух операций одновременно. Используются они следующим образом:

SetSizeClear<NOTIFYICONDATA> notify_icon;
notify_icon.hWnd = ...
notify_icon.hIcon = ....
...
Shell_NotifyIcon(NIM_ADD, &notify_icon);

Первая строчка заполняет структуру нулями и устанавливает член NOTIFYICONDATA::cbSize.

Остальные шаблоны используются аналогично.

Этот же механизм можно использовать для инициализации глобальных переменных или членов класса. Замечательно то, что инициализацию по умолчанию не надо будет явно прописывать в списке инициализации конструктора.

class KWindow : public CWnd
{
 ...
 SetSizeClear<NOTIFYICONDATA> notify_icon;
 ...
};

Инициализация будет выполнена до выполнения тела конструктора.

Заключение

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

Инициализация может выполняться не только шаблонами. Один из распространенных вариантов – использование инициализационной функции. Ее тоже можно сделать в виде шаблона, чтобы она могла работать с разными типами. В итоге – опять использование шаблонов.

Шаблоны из данной статьи можно усовершенствовать. Например, можно сделать универсальный шаблон для структур, который будет автоматически определять наличие cbSize. Этот же подход можно распространить и на другие признаки.


Если вам нравиться эта рассылка рекомендуйте ее своим друзьям. Подписаться можно по адресу http://subscribe.ru/catalog/comp.soft.prog.devdoc

Copyright (C) Kudinov Alexander, 2006-2007

Перепечатка и использование материалов запрещена без писменного разрешения автора.


В избранное