Класовете QString и QVariant

Низовете се използват в почти всички програми също толкова често, колкото и другите типове.

Езикът C++ предоставя два типа низове: традиционни низове на C, масиви от символи, завършващи с '\0', и клас низове. Qt предоставя много по-мощен клас QString. Той е предназначен да съхранява низове с 16-битови Unicode знаци. Unicode съдържа наборите от ASCII и Latin-1 символи с техните нормални цифрови стойности. Но тъй като всеки символ в QString е представен от 16 бита, той може да съдържа хиляди други символи. За повече информация относно Unicode вижте глава 15.

Конкатенацията на два QString може да се извърши с двойния оператор "+" или оператора "+=". Следва пример за използване на двата оператора:

Освен това има функцията QString::append(), която е идентична по действие с оператора "+=": И един напълно различен подход за конкатениране на низове е да се използва функцията QString::sprintf(): Тя поддържа същия набор от спецификатори на формат като библиотечната функция sprintf(). В примера по-горе низът str ще съдържа низа "перфектна конкуренция 100,0%".

Друг начин за "сглобяване" на низ от други низове и числа е да използвате arg():

В този пример "%1" ще бъде заменено с "permissive", "%2" с "society", "%3" с "1950" и "%4" с "1970". Резултатът е низът "разрешително общество (1950-1970)". Класът има няколко претоварени arg() функции за обработка на различни типове данни. Някои от тях имат допълнителни параметри, които контролират дължината на изходния низ, основата на бройната система и точността на представяне на числата с плаваща запетая. В повечето случаи arg() е по-добро решение от sprintf(), защото е по-безопаснонапълно поддържа Unicode и позволява на преводачите да променят реда на параметрите "%n".

QString ви позволява да преобразувате числа в тяхното низово представяне с помощта на статичната функция QString::number():

или с QString::setNum(): Обратното преобразуване може да се извърши от функциите toInt(), toLongLong(), toDouble() и т.н., например: Тези функции могат да приемат незадължителен аргумент bool, който връща индикатор за успех за преобразуването. Ако преобразуването не може да бъде извършено, те винаги връщат 0.

Често има ситуация, когато е необходимо да се извлече част от низ. Функцията mid() връща подниз с дадена дължина, започвайки от дадената позиция в изходния низ. Например, следният код отпечатва низа "плаща":

Ако пропуснете втория аргумент (или подадете -1 като втори аргумент), функцията ще върне подниз от дадената позиция до края на изходния низ. Например, следният код ще отпечата низа "принцип на плащане": Освен това има функции left() и right(). И двете приемат n знака и връщат съответно първите или последните n знака от оригиналния низ. Например, следният код ще изведе низа "принцип на замърсител": Ако искате да проверите дали даден низ започва или завършва с определена комбинация от знаци, има функции startsWith() и endsWith() за тази цел: Това е много по-бързо и лесно от: Операторът за сравнение на низове "==" е чувствителен към главни и малки букви. За да извършите сравнение без значение за главни и малки букви, можете да използвате функциите upper() или lower(), например: За да замените един подниз в низ с друг подниз, използвайте функцията replace(): резултатът ще бъде низът „облачен ден“. Същото действие може да се извърши сФункции remove() и insert(): Пет знака се премахват от първия ред, като се започне от 2-ра позиция, което води до низа „един ден“ (с два интервала), след което думата „облачно“ се вмъква на втората позиция.

Има претоварени версии на функцията replace(), които заместват всички срещания на първия аргумент с втория. Например, за да замените всички знаци с '&' в съответствие с "&":

Много често има нужда да се изхвърлят всички допълнителни бели знаци (като интервали, табулатори, нови редове) от началото и края на реда. Функцията stripWhiteSpace() съществува за тази цел: Низът str може да бъде начертан като:

Низовете могат да бъдат разделени на поднизове с помощта на функцията QStringList::split(): В този пример низът "принцип замърсителят плаща" е разделен на три подниза; "замърсител", "плаща" и "принцип". Функцията split() може да приеме незадължителен трети bool параметър, който указва дали празните поднизове трябва да се игнорират (по подразбиране) или не.

Елементите на QStringList могат да бъдат комбинирани в един низ с помощта на функцията join(). Той приема като аргумент низ, който да бъде вмъкнат между низовете, които ще бъдат свързани. Например, следният код демонстрира как можете да свържете всички низове в сортиран по азбучен ред списък в един низ, като поднизовете са разделени един от друг със знак за нов ред:

Друга важна операция върху низове е определянето на дължината на низ. Това е функцията length() и алтернативно isEmpty(), която връща true, ако дължината на низа е 0.

QString прави разлика между празни низове и несъществуващи (NULL) низове. Тези разлики се коренят в езика за програмиране C. За да проверите дали низ съществува, можете да извикатефункция isNull(). За повечето приложения е много важно да знаете дали даден низ съдържа поне един знак. Функцията isEmpty() ще върне true, ако низът не съдържа никакви знаци (празен или несъществуващ низ).

Конверсиите между const char * и QString се извършват автоматично в повечето случаи:

Този код добавя низ от тип const char * към низ от тип QString.

В някои ситуации става необходимо изрично преобразуване между const char * и QString. За да конвертирате QString в const char *, използвайте функцията ascii() или latin1(). Обратното преобразуване може да се извърши с операция за кастинг.

Когато се извикат функциите ascii() или latin1() или когато се извърши автоматично преобразуване в const char *, върнатият низ принадлежи на обект QString. Това означава, че не трябва да се тревожим за изтичане на памет - Qt се справя с паметта сам, според нуждите. От друга страна, трябва да се внимава много, когато се работи с указатели. Например, ако оригиналната версия на QString бъде променена, тогава полученият преди това указател към const char * може да не е валиден. Ако трябва да запазите предишната версия на низа, тогава за тези цели можете да използвате услугите на класа QByteArray или QCString. Те съхраняват пълно копие на данните.

Красотата на имплицитното споделяне на данни е, че оптимизира скоростта на операциите, без да се налага да го помним през цялото време – то просто работи!

Qt използва тази техника за оптимизация и за други класове, включително: QBrush, QFont, QPen, QPixmap, QMap, QValueList и QValueVector. Което подобрява ефективността на предаване на екземпляри на класстойност, както като аргументи на функцията, така и като връщани стойности.

C++ е строго типизиран език, но понякога става необходимо данните да се съхраняват по по-общ начин. Най-лесният начин е да използвате низове. Например низовете могат да съхраняват текстови или числови данни. Qt предоставя по-лесен начин за работа с променливи, класът QVariant.

Класът QVariant може да съхранява стойности на много типове Qt: QBrush, QColor, QCursor, QDateTime, QFont, QKeySequence, QPalette, QPen, QPixmap, QPoint, QRect, QRegion, QSize и QString. , за да съхранява съдържанието на клетката.

Една често срещана употреба на класа QVariant е за създаване на речници (карти), които използват низове като ключове и екземпляри на QVariant като стойности. Обикновено информацията за конфигурацията на приложението се съхранява и зарежда с помощта на QSettings, но понякога приложенията могат да обслужват настройки директно, например като ги съхраняват в база данни. QMap е идеален в следните ситуации:

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

Тук низът "Humpty" се записва на str1 и след това се присвоява на str2. Отсега нататък и двете променливи сочат към една и съща структура от данни в паметта (от тип QStringData). Заедно спо символи на низ, той съхранява препратен брой, който съдържа броя на обектите, които се отнасят към него. Тъй като и str1, и str2 се отнасят за едни и същи данни, броят на препратките е 2. Когато се направи промяна в съдържанието на str2, първо се създава пълно копие на данните, така че сега str1 и str2 се отнасят за различни структури и всички промени ще бъдат направени в техните собствени копия на данните. Броят на препратките на str1 ("Humpty") вече е 1, а броят на препратките на str2 ("Dumpty") също е 1. Когато броят на препратките е 1, това означава, че данните се използват само от един обект. Ако сега модифицираме променливата str2, тогава няма да се извърши копиране, тъй като броячът на препратките е 1. Функцията truncate() ще работи с данните, принадлежащи на променливата str2, а броячът на препратките ще остане равен на 1. След такова присвояване броят на препратките на променливата str1 ще стане равен на 0, което означава, че низът "Humpty" вече не е необходим. В този случай паметта, заета преди това от str1, ще бъде освободена. И двете променливи сега ще се отнасят към низа „Dump“ и броят на препратките ще бъде 2.

Създаването на класове, които използват имплицитната оптимизация за споделяне на данни, е доста лесно. Статията на Qt Quarterly „Споделяне на данни с клас“ (http://doc.trolltech.com/qq/qq02-data-sharing-with-class.html) описва как да направите това.

Преминаването през елементите на речник, който съхранява стойности във вариантна форма, може да не е толкова лесна задача, ако някои от стойностите са контейнери. За да проверите типа на стойността на варианта, трябва да използвате функцията type():

С QVariant можете да създавате красивисложни структури от данни, съхраняващи стойности от тип контейнер: В този пример беше създаден речник с ключове на низ (име на продукт) и стойности от двоен тип (цена) или тип QMap. Речникът от най-високо ниво съдържа три ключа: "Портокал", "Круша" и "Ананас". Стойността, свързана с ключа „Круша“, е речник с два ключа („Стандартен“ и „Органичен“).

Възможността да създавате структури от данни като тази може да бъде много изкушаваща, тъй като можете да структурирате данните, както желаете. Но удобството на QVariant е скъпо. В името на четливостта ще трябва да пожертвате скоростта.