При виде заголовка возможно сразу появился вопрос: зачем писать очередной класс строки, когда таких написано достаточно, в стандартной библиотеке есть и вряд ли можно сделать лучше?
Очень краткая предыстория: велась разработка под ПЛК ICP DAS I-7188XAD и писать код приходилось на Turbo C++ 1.01. Разработка возможна и на более поздних версиях компилятора до 3.1 включительно, а также на MS VC++ 5, но все же код, сгенерированный этим компилятором, работает наиболее стабильно. Turbo C++, конечно, не Си, однако нет шаблонов и, соответственно, STL, а также многих других приятных современных плюшек. Поэтому появилась необходимость создания класса для хранения строк, на основе которого реализованы также класс обработки DCON-запросов и класс для работы с дисплеем контроллера.
Цель: класс строки, компилируемый на Turbo C++ 1.01, фактически - динамический массив с использованием стандартной библиотеки Си для обработки строк и символов.
Интерфейс: несколько конструкторов, несколько операторов присваивания, конкатенации, преобразование в разнообразные арифметические типы и обратно, обрезка, вырезание частей и т.д.
Использование памяти: учитывая тот факт, что класс создавался для контроллера, имеющего крайне ограниченный объем памяти, использование памяти сведено к минимуму, что в свою очередь ведет к потере производительности. Любое изменение размера строки приводит к вызовам free() / calloc(), и размер буфера не превышает размера хранимых данных. Однако, на практике сколько-нибудь значимого снижения производительности не замечено.
Получилось примерно так:
class CString
{
public:
// Конструкторы
CString();
CString(const CString& s);
CString(const char* str);
// Деструктор. Вызывает Destroy();
~CString();
// Неявное преобразование в char*
char* GetString() const;
// Очищает и выделяет 1 байт под '\0'
void Clear();
BOOL IsEmpty() const;
// Получить целое число из строки. В строке должно
// находится число в десятичной системе счисления
int GetInt() const;
static int GetHexInt(const CString& str);
// То же, что GetInt(), но для шестнадцатеричной
// системы счисления
int GetHexInt() const;
float GetFloat() const;
// Получить строку из числа
static void FromInt(CString& s, int val);
void FromInt(const int val);
static void FromIntHex(CString& s, const int val);
void FromIntHex(const int val);
static void FromFloat(CString& s, float val);
void FromFloat(float val);
//Операторы BOOL operator==(const CString& s) const;
BOOL operator==(const char* chr) const;
BOOL operator!=(const CString& s) const;
CString& operator=(const CString& s);
CString& operator=(const char* s);
CString& operator=(const char c);
CString& operator+=(const CString& s);
CString& operator+=(char c);
CString& operator+=(const char* chr);
const CString operator+(const CString& s) const;
const CString operator+(const char* s) const;
const CString operator+(char s) const; operator char*() const;
//Манипуляции со строками
static BOOL Compare(const CString& s1, const CString& s2, BOOL bCaseSensetive);
BOOL Compare(const CString& str, BOOL bCaseSensetive) const;
BOOL Compare(const char* chr, BOOL bCaseSensetive) const;
static void ToUpper(CString& s);
void ToUpper(); void ToLower();
void TrimLeft();
void TrimRight();
void Trim();
BOOL Crop(unsigned int indexFrom, unsigned int indexTo);
BOOL Cut(unsigned int indexFrom, unsigned int indexTo);
protected:
// Очистка памяти
void Destroy();
// Выделение памяти
void Allocate(unsigned int nChars);
private:
// Указатель на массив символов
char* m_pString;
// Длина строки в символах
unsigned int m_nLen;
};
Скорее всего, даже такой скромный интерфейс избыточен для работы в ПЛК. При работе с протоколом DCON удобно использовать методы преобразования строки к числу и наоборот.
Класс небольшой и размещен в одном файле. Теперь можно применить этот класс для обработки аргументов функции main(), например:
#include "VLCSTR.H"
int main(int argc, char** argv)
{
if(argc>=2)
{
CString s(argv[1]);
int n=s.GetInt();
//Работа с n...
}
return 0;
}
DCON-запросы на модули ввода/вывода являются ANSI-строками с терминатором \r , поэтому класс CString вполне сгодится для создания класса, создающего запросы на модули, и обрабатывающего ответы от них. Назовем его CDconString...