Цитата |
Итак, мы начинаем балл! |
Сегодня мы поработаем над парой базовых классов для нашего проекта. А именно:
- Класс строки
- Вектора
- Двусвязанного списка
Сразу хочется сказать, что файлы реализации (*.cpp) мы будем ложить в директорию "cpp", а файлы описания в "inc", обе папки лежат в одной директории.
Я советую вам создать пустой “win32 console” проект и в нём время от времени дебажить некие маленькие алгоритмы. В частности, сейчас будем писать класc строки.
Называйте, как хотите, а у меня это класс “aString”. Что должен будет уметь наш класс?
- Хранить данные как в wchar_t, так и char
- Складывать две строки
- Сравнивать две строки
- Искать строку до опред. символа
- Искать строку после опред. символа
Итак содаём файл описания класса (
astring.h):
Код |
//=============================================================================
#ifndef ASTRING_H #define ASTRING_H
//=============================================================================
#include <windows.h>
//=============================================================================
class aString { public: aString();//конструктор всех видов aString(const wchar_t* str); aString(const char* str); aString(const aString& str);
inline size_t asGetLength()const {return m_Length;} inline const wchar_t* asGetString()const {return m_pData;} inline const char* asGetStringChar()const {return m_pCharData;} inline UINT asGetCodePage()const {return codePage;} inline size_t asGetCharSize()const {return charSize;}
bool operator==(const aString& str); bool operator==(const wchar_t* str); bool operator==(const char* str); bool operator!=(const aString& str); bool operator!=(const wchar_t* str); bool operator!=(const char* str); const aString operator=(const aString& str); const aString operator=(const wchar_t* str); const aString operator=(const char* str); const aString operator+=(const aString str); const aString operator+=(const wchar_t* str); const aString operator+=(wchar_t chr);
aString asFindBefore(wchar_t chr, bool include);//вернуть строку до опред. символа aString asFindAfter(wchar_t chr, bool include);//вернуть строку после опред. символа void asClear();//отчистить строку
~aString();
private: size_t m_Length; wchar_t* m_pData; char* m_pCharData; const size_t charSize; UINT codePage; UINT codePageW; };
//=============================================================================
#endif
//============================================================================= |
Вообщем – то здесь всё прозрачно и ясно. Конкретная реализация идёт дальше: тут вам придётся поработать самим в некоторых местах.
astring.cppКод |
//=============================================================================
#include <string.h> #include "../inc/aString.h"
//=============================================================================
aString::aString() : charSize(sizeof(wchar_t))//частенько используется размер wchar_t: думаю логично было бы его зафиксировать. Char = 1 { m_Length = 0; m_pData = 0; m_pCharData = 0; codePage = CP_UTF8;//код для преобразования из wchar_t в char codePageW = CP_UTF8;//наоборот }
//=============================================================================
aString::aString(const wchar_t* str) : charSize(sizeof(wchar_t)) { m_Length = 0; m_pData = 0; m_pCharData = 0; codePage = CP_UTF8; codePageW = CP_UTF8;
if (!str) return;
size_t strLen = wcslen(str); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pData, str, strLen*charSize); m_pData[strLen] = 0;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
m_pCharData[strLen] = 0;
m_Length = strLen; }
//=============================================================================
aString::aString(const char* str) : charSize(sizeof(wchar_t)) { m_Length = 0; m_pData = 0; m_pCharData = 0; codePage = CP_UTF8; codePageW = CP_UTF8;
if (!str) return;
size_t strLen = strlen(str); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pCharData, str, strLen); m_pCharData[strLen] = 0;
//здесь должна быть функция преобразования char в wchar_t. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
m_pData[strLen] = 0;
m_Length = strLen; }
//=============================================================================
aString::aString(const aString& str) : charSize(sizeof(wchar_t)) { m_Length = 0; m_pData = 0; m_pCharData = 0; codePage = CP_UTF8; codePageW = CP_UTF8;
if (str.asGetLength() <= 0) return;
const wchar_t* tmpPointer = str.asGetString(); size_t strLen = wcslen(tmpPointer); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pData, tmpPointer, strLen*charSize); m_pData[strLen] = 0;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитес использовать. Все данные у вас есть.
m_pCharData[strLen] = 0;
m_Length = strLen; }
//=============================================================================
bool aString::operator==(const aString& str) { if (str.asGetLength() != m_Length) return 0;
wchar_t* tmpPointer = m_pData; const wchar_t* tmpPointer2 = str.asGetString(); while(*tmpPointer != L'\0') { if (*tmpPointer++ != *tmpPointer2++) return 0; }
return 1; }
//=============================================================================
bool aString::operator==(const wchar_t* str) { if (!str) return 0;
if (wcslen(str) != m_Length) return 0;
wchar_t* tmpPointer = m_pData; while(*tmpPointer != L'\0') { if (*tmpPointer++ != *str++) return 0; }
return 1; }
//=============================================================================
bool aString::operator==(const char* str) { if (!str || !m_pCharData) return 0;
if (strlen(str) != m_Length) return 0;
char* tmpPointer = m_pCharData; while(*tmpPointer != L'\0') { if (*tmpPointer++ != *str++) return 0; }
return 1; }
//=============================================================================
bool aString::operator!=(const aString& str) { if (str.asGetLength() != m_Length) return 1;
wchar_t* tmpPointer = m_pData; const wchar_t* tmpPointer2 = str.asGetString(); while(*tmpPointer != L'\0') { if (*tmpPointer++ != *tmpPointer2++) return 1; }
return 0; }
//=============================================================================
bool aString::operator!=(const wchar_t* str) { if (!str) return 1;
if (wcslen(str) != m_Length) return 1;
wchar_t* tmpPointer = m_pData; const wchar_t* tmpPointer2 = str; while(*tmpPointer != L'\0') { if (*tmpPointer++ != *tmpPointer2++) return 1; }
return 0; }
//=============================================================================
bool aString::operator!=(const char* str) { if (!str) return 1;
if (strlen(str) != m_Length) return 1;
wchar_t* tmpPointer = m_pData; while(*tmpPointer != L'\0') { if (*tmpPointer++ != *str++) return 1; }
return 0; }
//=============================================================================
const aString aString::operator=(const aString& str) { if (str.asGetLength() <= 0) return (*this);
const wchar_t* tmpPointer = str.asGetString(); size_t strLen = wcslen(tmpPointer); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pData, tmpPointer, strLen*charSize); m_pData[strLen] = 0;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
m_pCharData[strLen] = 0;
m_Length = strLen;
return (*this); }
//=============================================================================
const aString aString::operator=(const wchar_t* str) { if (!str) return (*this);
size_t strLen = wcslen(str); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pData, str, strLen*charSize); m_pData[strLen] = 0;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
m_pCharData[strLen] = 0;
m_Length = strLen;
return (*this); }
//=============================================================================
const aString aString::operator=(const char* str) { if (!str) return (*this);
size_t strLen = strlen(str); m_pData = new wchar_t[strLen + 1]; m_pCharData = new char[strLen + 1]; memcpy(m_pCharData, str, strLen); m_pData[strLen] = 0;
//здесь должна быть функция преобразования char в wchar_t. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
m_Length = strLen;
return (*this); }
//=============================================================================
const aString aString::operator+=(const aString str) { if (str.asGetLength() <= 0) return (*this);
size_t newLength = str.asGetLength() + m_Length; wchar_t* newData = new wchar_t[newLength + 1]; char* newData2 = new char[newLength + 1];
memcpy(newData, m_pData, m_Length*charSize); memcpy(&newData[m_Length], str.asGetString(), str.asGetLength()*charSize); newData[newLength] = 0; delete [] m_pData; delete [] m_pCharData;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
newData2[newLength] = 0;
m_pData = newData; m_pCharData = newData2; m_Length = newLength;
return (*this); }
//=============================================================================
const aString aString::operator+=(const wchar_t* str) { if (!str) return (*this);
size_t tmpLength = wcslen(str);
if (tmpLength <= 0) return (*this);
size_t newLength = tmpLength + m_Length; wchar_t* newData = new wchar_t[newLength + 1]; char* newData2 = new char[newLength + 1];
memcpy(newData, m_pData, m_Length*charSize); memcpy(&newData[m_Length], str, tmpLength*charSize); newData[newLength] = 0; delete [] m_pData; delete [] m_pCharData;
//здесь должна быть функция преобразования wchar_t в char. Покумекайте сами, найдите описание и научитесь использовать. Все данные у вас есть.
newData2[newLength] = 0;
m_pData = newData; m_pCharData = newData2; m_Length = newLength;
return (*this); }
//=============================================================================
const aString aString::operator+=(wchar_t str) { size_t newLength = m_Length + 1; wchar_t* newData = new wchar_t[newLength + 1];
memcpy(newData, m_pData, m_Length*charSize); memcpy(&newData[m_Length], &str, charSize); newData[newLength] = 0; if (m_Length > 0) delete [] m_pData;
m_pData = newData; m_Length = newLength;
return (*this); }
//=============================================================================
aString aString::asFindBefore(wchar_t chr, bool include) { wchar_t* tmpPointer = m_pData; aString res;
while(*tmpPointer != L'\0') { if (*tmpPointer != chr) res += *tmpPointer++; else { if (include) res += *tmpPointer;
break; } }
return res; }
//=============================================================================
aString aString::asFindAfter(wchar_t chr, bool include) { wchar_t* tmpPointer = m_pData; aString res; bool find = 0;
while(*tmpPointer != L'\0') { if ((*tmpPointer == chr) && (!find)) { find = 1; if (!include) { ++tmpPointer;
continue; } }
if (find) res += *tmpPointer;
++tmpPointer; }
return res; }
//=============================================================================
void aString::asClear() { if (m_pData) { delete [] m_pData;
m_pData = 0; } if (m_pCharData) { delete [] m_pCharData;
m_pCharData = 0; } m_Length = 0; }
//=============================================================================
aString::~aString() { asClear(); }
//============================================================================= |
Получается, что в первой нашей части теории практической никакой нет: просто отрабатываем общие принципы создания классов и включаем воображалку.
Идём дальше.
Двусвязанный списокОн состоит из одного файла описания, потому что будет основан на шаблонах.
aList.hКод |
//==============================================================================
#ifndef ALIST_H #define ALIST_H
//==============================================================================
template <class TypeItem> class aItem { public: aItem<TypeItem>() { next = 0; prev = 0; }; ~aItem<TypeItem>() { }; aItem* next; aItem* prev; TypeItem data; };//класс – элемент нашего списка.
//==============================================================================
template <class Type> class aList { public: inline aItem<Type>* alGetLastItem() const {return last;} inline aItem<Type>* alGetFirstItem() const {return items;} inline int alGetCount() const {return count;}
aList() { items = 0; last = 0; count = 0; } ~aList() { alRemoveItems(); }
aItem<Type>* alAddItem() { if (!items) { items = new aItem<Type>; last = items; ++count; return items; } aItem<Type>* tmpItem = this->alGetLastItem();
tmpItem->next = new aItem<Type>; tmpItem->next->prev = tmpItem;
last = tmpItem->next; ++count; return last; } void alRemoveItems() { if (!items) return;
aItem<Type>* tmpItem = alGetLastItem(); aItem<Type>* tmpItem2 = 0; while(1) { tmpItem2 = tmpItem->prev; delete tmpItem; if (tmpItem2) tmpItem = tmpItem2; else break; } items = 0; last = 0; count = 0; } void alRemoveLastItem() { if (items) { if (last->prev) { last->prev = 0;
delete last; } else { delete items; items = 0; } last = 0; --count; } } void alRemoveItem(aItem<Type>* it) { //а вот тут помучайтесь и напиши функцию, которая будет удалять любой элемент нашего списка. Не забывайте про исключительные ситуации и проверить находится ли этот элемент вообще в нашем списке. } private: bool alFoundItem(aItem<Type>* it)//функция проверяет: есть ли такой объект в нашем списке. { //тоже подумайте как написать }
private: aItem<Type>* items; aItem<Type>* last; int count; };
//==============================================================================
#endif
//============================================================================== |
Помните: чем больше исключений вы обработаете и отбросите – тем стабильнее будет ваш код. В идеале, программист должен уметь предусмотреть абсолютно все варианты, которые могут привести к крушению приложения.
Дальше, по программе – чай с сахаром, а затем маленький класс вектора, который будет использован для больших деяний ;-)
avector.hКод |
//=============================================================================
#ifndef AVECTOR_H #define AVECTOR_H
//=============================================================================
#include <math.h>
//=============================================================================
class aVector { public: inline const aVector& operator=(const aVector& vec) { this->x = vec.x; this->y = vec.y; this->z = vec.z;
return (*this); } inline bool operator==(const aVector& vec) {}//реализуйте самостоятельно сравнение двух векторов. Помните что напрямую сравнить два float числа вы не можете: работа над числами с плавующей точкой весьма бажна. Шустри гуглом, думайте: это не сложно. inline bool operator==(const aVector& vec)const {} inline bool operator!=(const aVector& vec) {} inline bool operator!=(const aVector& vec)const {} inline const aVector operator+(const aVector& vec)const { aVector tmpVector((*this));
tmpVector.x += vec.x; tmpVector.y += vec.y; tmpVector.z += vec.z;
return tmpVector; } inline const aVector operator-(const aVector& vec)const { aVector tmpVector((*this));
tmpVector.x -= vec.x; tmpVector.y -= vec.y; tmpVector.z -= vec.z;
return tmpVector; } inline const aVector operator+=(const aVector& vec) { this->x += vec.x; this->y += vec.y; this->z += vec.z;
return (*this); } inline const aVector operator-=(const aVector& vec) { this->x -= vec.x; this->y -= vec.y; this->z -= vec.z;
return (*this); } inline const aVector operator*(float num)const { aVector tmpVector((*this));
tmpVector.x *= num; tmpVector.y *= num; tmpVector.z *= num;
return tmpVector; } inline const aVector operator/(float num)const { aVector tmpVector((*this));
tmpVector.x /= num; tmpVector.y /= num; tmpVector.z /= num;
return tmpVector; } inline const aVector operator*=(float num) { this->x *= num; this->y *= num; this->z *= num;
return (*this); } inline const aVector operator/=(float num) { this->x /= num; this->y /= num; this->z /= num;
return (*this); }
aVector(); aVector(float, float, float); aVector(const aVector&); void avSet(float, float, float); ~aVector();
public: float x, y, z; };
//=============================================================================
#endif
//============================================================================= |
Ну и файл реализации (
avector.cpp):
Код |
//=============================================================================
#include "../inc/aVector.h"
//=============================================================================
aVector::aVector() { this->x = 0; this->y = 0; this->z = 0; }
//=============================================================================
aVector::aVector(float xx, float yy, float zz) { this->x = xx; this->y = yy; this->z = zz; }
//=============================================================================
aVector::aVector(const aVector& vec) { this->x = vec.x; this->y = vec.y; this->z = vec.z; }
//=============================================================================
void aVector::avSet(float xx, float yy, float zz) { this->x = xx; this->y = yy; this->z = zz; }
//=============================================================================
aVector::~aVector() { }
//============================================================================= |
Слов и аналитики мало, потому что тут голые и незамороченные факты.
Спрашивайте, пишите, подскажу, если что ;-)
Да прибудет с вами великая сила!
Добавлено @ 15:11Поиграйтесь с классами, поищите баги у меня в коде, предложите свои улучшения, научитесь всем пользоваться: вы большие мальчики/девочки - сможете.
Это сообщение отредактировал(а) Rickert - 20.10.2008, 03:45