С++ - язык, который изучается постепенно.Пример

Недорогой но высококачественный сайт. Такое может быть? Да. У нас может быть всё. Достойное качество по доступной цене.
С точки зрения нашей студии создание сайта недорого значит, прежде всего, отменно, технологично и потом уже - недорого.
Удаленная форма работы с клиентами оптимизирует наши расходы и мы можем делать сайты по всему миру. Вам совсем не нужно приезжать к нам. Мы сэкономим Ваше время и средства.

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


По последним данным, на рынке продается по крайней мере 2 768 942 книги о С++, не говоря уже о всевозможных курсах, обучающих программах, журналах и семинарах с коктейлями. И все же в этом изобилии наблюдается удручающее однообразие. Просматривать полку книг о С++ в книжном магазине ничуть не интереснее, чем литературу по бухгалтерии. В сущности, все книги пересказывают одно и то же и отличаются разве что по весу и количеству цветов в диаграммах и таблицах.На сегодняшний день язык Си и языки основанные на синтаксисе Си (например, C++, Java, C#) наиболее популярны в практическом программировании. Язык Си имеет массу достоинств, он прост в изучении и лаконичен. Элементы языка Си (массивы, функции, указатели) максимально приближены к архитектуре компьютеров. Студия Web-дизайна, создание, раскрутка сайта

                    



Материалы книги получены с http://www.itlibitum.ru/

Пример

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

Ненадежный коммерческий класс словаря

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

class Dictionary {

public:

Dictionary(); // Создает пустой словарь

Dictionary(const Dictionary&); // Конструктор копий

~Dictionary();

Dictionary& operator=(const Dictionary&);

void AddEntry(void* key, void* value);

bool At(void* key, void*& value);

void RemoveEntry(void* key);

typedef void* Slot; // Настоящее объявление надежно спрятано

Slot First(); // Возвращает Slot для перебора

// Эквивалент нашей функции "Peek"

bool GetCurrent(Slot slot, void*& key, void*& value);

// Эквивалент нашей функции "Next"

bool GetNext(Slot& slot, void*& key, void*& value);

};

Функция AddEntry() заносит в словарь новое значение с заданным ключом. Если ключ уже

существует для другого значения, значение заменяется новым. Функция At() возвращает логический код, который показывает, присутствует ли ключ в словаре; если присутствует, функция возвращает true и value (значение, соответствующее данному ключу). Функция RemoveEntry() удаляет ключ и связанное с ним значение. Функция First() возвращает пассивный итератор, направленный таким образом, чтобы первый вызов GetNext() возвратил первый элемент словаря. Функция GetCurrent() возвращает пару ключ/значение, находящуюся в текущей позиции Slot. Функция GetNext() возвращает пару ключ/значение и перемещает итератор к следующему элементу. Единственное отличие между этими функциями заключается в перемещении логической позиции после получения объекта. Мы воспользуемся словарем следующим образом: ключом будет объект, хранящийся в нашем наборе, а значением этого ключа - журнал вставок/удалений для данного объекта.

Класс журнала

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

class History {

public:

History(); // Пустой журнал

void Insert(Timestamp); // Вставка в заданное время

void Remove(Timestamp); // Удаление в заданное время

bool Exists(Timestamp); // В заданное время

bool Exists(); // В настоящий момент

};

Функция Exists(Timestamp) возвращает true, если в заданное время последней операцией была

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

Абстрактный базовый класс

Класс набора делится на две части: абстрактный базовый класс, работающий с void*, и производный параметризованный класс, в который добавлена безопасность типов. Абстрактный базовый класс выглядит так:

// В файле Set.h

class SetBase : private Dictionary {

friend class InternalIterator;

protected:

SetBase(); // Чтобы класс был абстрактным

public:

class Iterator { // Базовый класс внешнего итератора

public:

virtual bool More() = 0;

virtual Type* Next() = 0;

};

};

Iterator* SetBase::ProvideIterator()

{

return new InternalIterator(this);

}

void SetBase::AddObject(void* entry)

{

void* v;

History* h;

if (At(entry, v)) { // Уже есть - проверить время

h = (History*)v;

if (!h->Exists()) // Необходимо выполнить вставку

h->Insert(Timestamp());

}

else { // Еще нет

h = new History;

h->Insert(Timestamp());

AddEntry(entry, h);

}

}

void SetBase::RemoveObject(void* entry)

{

void* v;

History* h;

if (At(entry, v)) { // Уже есть - проверить время

h = (History*)v;

if (h->Exists()) // Необходимо выполнить удаление

h->Remove(Timestamp());

}

}

bool SetBase::Exists(void* entry, Timestamp ts)

{

void* v;

return At(entry, v) && ((History*)v)->Exists(ts);

}

bool SetBase::Exists(void* entry)

{

void* v;

return At(entry, v) && ((History*)v)->Exists();

}

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

Внутренний итератор

Чтобы реализовать функцию ProvideIterator(), мы создаем как нетипизированный внутренний

итератор, ограниченный файлом .cpp и производный от SetBase::Iterator, так и внешний - в виде параметризованной, безопасной по отношению к типам оболочки. Ниже приведен код внутреннего итератора, объявленного статически (то есть локального по отношению к файлу .cpp). Вся логика временных пометок спрятана в реализации этого класса.

// В файле set.cpp

class InternalIterator : public SetBase::Iterator {

private:

Dictionary* dictionary;

Dictionary::Slot* slot; // Текущая позиция

Timestamp my_time; // Время рождения данного итератора

public:

InternalIterator(Dictionary* d)

: dictionary(d), slot(d->First()), my_time() {}

virtual bool More();

virtual void* Next();

};

bool InternalIterator::More()

{

void* key;

void* h;

if (!dictionary->GetCurrent(slot, key, h))

return false; // позиция выходит за текущие границы

do

if (((History*)h)->Exists(my_time))

return true;

while (dictionary->GetNext(slot, key, h));

return false;

}

void* InternalIterator::Next()

{

void* key;

void* key1;

void* h;

// Предполагается, что клиент сначала вызвал More(),

// поэтому объект GetNext() не устарел

dictionary->GetCurrent(slot, key, h);

dictionary->GetNext(slot, key1, h);

return key;

}

Параметризованная оболочка, безопасная по отношению к типам

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

template <class Type>

class Set : private SetBase {

public:

// Безаргументный конструктор - подходит

// Конструктор копий по умолчанию - подходит

// Оператор = по умолчанию - тоже подходит

Set<Type>& operator+=(Type* object)

{ AddObject(object); return *this; }

Set<Type>& operator-=(Type* object)

{ RemoveObject(object); return *this; }

bool operator>=(Type* object)

{ return Exists(object); }

class Iterator {

private:

SetBase::Iterator* iter;

public:

Iterator(Set&* i) : iter(s.ProvideIterator()) {}

bool More() { return iter->More(); }

Type* Next() { return (Type*)(iter->Next()); }

};

Iterator* ProvideIterator()

{ return new Set::Iterator(*this); }

};

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

Set::Iterator iter(aSet);

Такой вариант работает вполне нормально, однако он не соответствует обычной идиоме возвращения итератора из коллекции. Заслуживает внимания и другой вариант: сделать SetBase переменной класса вместо закрытого базового класса. Это позволит вам упрятать SetBase в файл .cpp, чтобы клиент никогда не видел его. Для этого в шаблоне Set придется определить конструкторы и оператор =, но все остальные модификации шаблона будут простыми и незамысловатыми.


Назад    Содержание    Далее    

   Почти всегда целью создания сайта является получение прибыли, которая в свою очередь, зависит от его внешнего вида. Статистика говорит, что около 94% людей, при выборе товара, сначала обращают внимание на упаковку, а потом уже на её содержимое. И если эта упаковка не привлекательная и безвкусная, мало кто обратит на нее внимание, и, соответственно, товар не будет пользоваться спросом.
   В случае с интернет, “упаковкой” выступает ваш сайт, а “товаром” - его контент. Если сайт выглядит непривлекательно, то каким бы ценным и нужным не было его содержимое, люди будут обходить его стороной. Наша задача - сделать ваш сайт привлекательным и удобным, чтобы люди чувствовали себя уютно и комфортно, чтоб они возвращались к вам еще и еще. Соответствие между ценой и качеством вас, несомненно, порадуют.
.
   Мы делаем сайты для бизнеса, а не красочную картинку, которая увешена тяжеловесными флэшами и огромными фотографиями.
   Пользователя, когда он попадает на абсолютно любой сайт, прежде всего интересует информация, затем, как реализовать на этом сайте полученную информацию, чтобы было удобно и просто (юзабилити), подбор цветовой гаммы, расположение блоков на странице и многое другое.

   Перед тем, как заказывать создание сайта, рекомендуем прочесть статью А зачем мне (нам) сайт? или Что нужно знать заказчику сайта
Да и вообще, обратите внимание на раздел Статьи о продвижении сайта и бизнеса там вы найдёте ответы на многие вопросы.