QVariant Internals/bg: Difference between revisions
AutoSpider (talk | contribs) (Add "cleanup" tag) |
AutoSpider (talk | contribs) (Remove non-functioning "toc" command) |
||
(3 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
'''Български''' [[QtVariant|English]] [[QtVariant SimplifiedChinese|简体中文]] | '''Български''' [[QtVariant|English]] [[QtVariant SimplifiedChinese|简体中文]] | ||
[[Category:QtInternals]] | [[Category:QtInternals]] | ||
= QtVariant = | = QtVariant = | ||
Line 15: | Line 14: | ||
Преди да разберем реализацията на Qt, първо ще се опитаме да разберем различните проблеми, включени в дизайна на QVariant, за да оценим по-добре крайното решение. | Преди да разберем реализацията на Qt, първо ще се опитаме да разберем различните проблеми, включени в дизайна на QVariant, за да оценим по-добре крайното решение. | ||
== Изисквания към функционалността на QVariant == | |||
# QVariant не трябва ( и не може) да бъде шаблонен клас. Ако QVariant е шаблонен, всеки клас, които съхранява QVariant трябва да стане. | # QVariant не трябва ( и не може) да бъде шаблонен клас. Ако QVariant е шаблонен, всеки клас, които съхранява QVariant трябва да стане. | ||
# QVariant трябва да работи както за POD (http://en.wikipedia.org/wiki/Plain_Old_Data_Structures), така и за не-POD типове данни. Трябва да работи с всеки тип, който може да се копира и да се държи като клас за съхранение на данни. Забележете, че поддръжката на не-POD типове, означава, че не може да се използва C типа ''union'' за съхранение на всички известни типове данни, тъй като C++ не позволява слагането на не-POD типове в ''union''. | # QVariant трябва да работи както за POD (http://en.wikipedia.org/wiki/Plain_Old_Data_Structures), така и за не-POD типове данни. Трябва да работи с всеки тип, който може да се копира и да се държи като клас за съхранение на данни. Забележете, че поддръжката на не-POD типове, означава, че не може да се използва C типа ''union'' за съхранение на всички известни типове данни, тъй като C++ не позволява слагането на не-POD типове в ''union''. | ||
Line 22: | Line 20: | ||
# QVariant не трябва (и не може) да използва C++ RTTI. В C+'', RTTI работи само с полиморфични класове. | # QVariant не трябва (и не може) да използва C++ RTTI. В C+'', RTTI работи само с полиморфични класове. | ||
== Съхванение на стойността като 'void '''' == | |||
Идейно би било да се пази 'void'''' и типа в QVariant. Може да имаме QVariant конструктор като функционален шаблон, който да пасва на всеки тип. Нещо като: | Идейно би било да се пази 'void'''' и типа в QVariant. Може да имаме QVariant конструктор като функционален шаблон, който да пасва на всеки тип. Нещо като: | ||
<code> | <code> | ||
Line 50: | Line 47: | ||
// За всички не-POD типове имаме шаблонен конструктор | // За всички не-POD типове имаме шаблонен конструктор | ||
template <typename T> | template <typename T> | ||
QVariant(const T & | QVariant(const T &t) | ||
{ | { | ||
data.v = (void''') new T (t); | data.v = (void''') new T (t); |
Latest revision as of 12:28, 17 April 2015
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine. Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean. |
QtVariant
Въведение
В C++ променливите трябва да имат тип, който да е известен по време на компилацията. Но има ситуации, които налагат да се използват променливи, чийто тип е известен само по време на изпълнение. На пример, нека да кажем, че имате функция, която връща стойност от база данни. Какъв ще бъде типа на върнатата стойност? В C, ще бъде "void " и допълнителна информация ще бъде предоставена за типа и. Или да предположим, че вие позволявате на потребителя да добавя произволна информация в клетките на разработена от вас таблица. Какъв тип трябва да бъде аргумента на тази функция - setUserCellData(type x)?
В тези ситуации може да се използва QVariant и той може да съхранява стойност от всеки тип. Вие можете да питате QVariant за типа и да обработите стойността, съхранена вътре подобаващо.
Преди да разберем реализацията на Qt, първо ще се опитаме да разберем различните проблеми, включени в дизайна на QVariant, за да оценим по-добре крайното решение.
Изисквания към функционалността на QVariant
- QVariant не трябва ( и не може) да бъде шаблонен клас. Ако QVariant е шаблонен, всеки клас, които съхранява QVariant трябва да стане.
- QVariant трябва да работи както за POD (http://en.wikipedia.org/wiki/Plain_Old_Data_Structures), така и за не-POD типове данни. Трябва да работи с всеки тип, който може да се копира и да се държи като клас за съхранение на данни. Забележете, че поддръжката на не-POD типове, означава, че не може да се използва C типа union за съхранение на всички известни типове данни, тъй като C++ не позволява слагането на не-POD типове в union.
- QVariant трябва да може да съхранява потребителски типове. Така, че ако напишете MyStruct, трябва да можете да я съхраните в QVariant.
- QVariant не трябва (и не може) да използва C++ RTTI. В C+, RTTI работи само с полиморфични класове.
Съхванение на стойността като 'void '
Идейно би било да се пази 'void' и типа в QVariant. Може да имаме QVariant конструктор като функционален шаблон, който да пасва на всеки тип. Нещо като:
class QVariant
{
private:
union {
// POD типове данни
int i;
float f;
// Всички не-POD типове данни се запазват като void *.
void '''v;
} data;
enum DataType { Integer, Float, NonPod }; // типа на данните
int type;
public:
// Конструктор за вградените/POD типове данни
QVariant(int i)
{
data.i = i;
type = Integer;
}
// За всички не-POD типове имаме шаблонен конструктор
template <typename T>
QVariant(const T &t)
{
data.v = (void''') new T (t);
type = NonPod;
…
}
Обаче имаме проблем, когато трябва да направим деструктор. Как да 'delete' void указател? В C+ не можете да унищожавате 'void''.
Намиране на решението
Както можем да се досетим от горния пример, за да унищожим void , ние просто трябва да знаем типа. И тъй като QVariant трябва да поддържа дефинирани от потребителя типове, не е възможно да се сложи един голям switch с reinterpret_cast на void към даден тип и да унищожим указателя.
Също имаме и проблем, когато искаме да вземем съдържанието на QVariant. variant.value<MyStruct>() не трябва да дава грешка при никакви обстоятелства. Ако конвертирането не е възможно, трябва да върнем променлива от тип MyStruct, създадена с конструктора му по подразбиране.
Решението е да имаме система, която може да конструира стойност от void , да унищожава void и да превръща void * в правилния тип, за да може да работи със стойността. Ако имаме функции за тези дейности за всеки тип, който може да се съхранява в QVariant, тогава QVariant може да използва тези функции за да работи с void *.
qMetaTypeConstructHelper и qMetaTypeDeleteHelper са помощни шаблонни функции qRegisterMetaType<MyStruct>("MyStruct")
— QMetaType::registerType("MyStruct", ctr, dtr); — Вътрешно всичко се пази в QVector<QCustomTypeInfo>
Ако направим qRegisterMetaType за всички типове, ще сме готови! Но това не е ли прекалено много работа? Q_DECLARE_METATYPE(Type)
—- Създава клас QMetaTypeId, който предоставя qt_metatype_id(), което регистрира при нужда.
— Предоставя функция