Я делаю редактор данных формата Json с поддержкой Qt treeview и Qt Json.
Я хочу передать ссылочный параметр QJsonObject или QJsonArray в функцию.
Это работает:
void makeJsonData(QJsonObject &obj) {
obj.insert("key", 1234);
}
//call makeJsonData()
QJsonObject jobj;
makeJsonData(jobj);
int keysize = jobj.keys().size(); //1, OK.
Но не с этим:
//QJsonValue, because it can handle both QJsonObject and QJsonArray
void makeJsonData(QJsonValue &obj) {
obj.toObject().insert("key", 1234); //obj is QJsonObject
}
//call makeJsonData()
QJsonObject jobj;
makeJsonData(QJsonValue::fromVariant(jobj)); //fromVariant() to cast QJsonObject to QJsonValue
int keysize = jobj.keys().size(); //0, Fail.
Похоже, QJsonValue :: toObject () просто копирует параметр ..
Как я могу использовать ссылки как QJsonObject, так и QJsonArray с одним типом параметра?
Есть несколько способов решить вашу проблему:
Опция 1 (как упоминалось в моем комментарии)
Динамическое приведение может быть использовано так:
bool makeJsonData(void* obj) {
QJsonObject* asObj = dynamic_cast<QJsonObject*>(obj);
QJsonArray* asArray = dynamic_cast<QJsonArray*>(obj);
if (asObj) {
//do what you would if it were an object
}
else if (asArray) {
//do what you would if it were an array
}
else {
//cast fail. Returning false to tell the caller that they passed bad data
//an alternate (probably better) would be to throw an exception
return false;
}
}
Вариант 2
Я честно чувствую, что это бизнес с void*
это неправильный способ сделать это. дела void*
материал почти всегда пахнет кодом (он убирает проверки во время компиляции, которые не дают нам встать на ноги), и в этом случае я думаю, что то, как вы это делаете, требует работы. Также, dynamic_cast
требует RTTI который не всегда может быть включен (поддержка компилятора, проблемы с производительностью и т. д.).
Я посмотрел на заголовки Qt на моей машине и, насколько я могу судить, QJsonObject
а также QJsonArray
на самом деле не наследовать от чего-либо, поэтому идти по пути изменения void*
к базовому типу, чтобы сохранить видимость проверки типов, не совсем сработает.
Что бы я сделал, было бы это:
QJsonObject createJsonData()
) и вызовите его внутри обоих ваших методов, упомянутых выше.Идея состоит в том, чтобы сохранить повторение кода при сохранении проверки типов. Время, которое вы тратите на создание одного дополнительного метода для обработки обоих случаев, может быть намного меньше, чем время, которое вы потратите на отладку кода после случайной передачи чего-либо void*
указатель, который вы никогда не хотели передавать.
Вариант 3
Вы также можете использовать QJsonValue
измените тип возвращаемого значения функции на QJsonValue
и заставить его вернуть новый объект без изменения оригинала. Кроме того, QJsonValue
класс развлекается isArray
/isObject
методы, которые вы могли бы использовать, чтобы сделать что-то вроде упомянутых ранее. Пример:
QJsonValue makeJsonData(const QJsonValue& val) {
if (val.isObject()) {
QJsonObject obj = val.toObject();
//do your stuff, modifying obj as you please (perhaps calling another method so that this can have less repetition
return QJsonValue(obj);
}
else if (val.isArray()) {
QJsonArray arr = val.toArray();
//do your stuff, modifying arr as you please (perhaps calling another method so that this can have less repetition
return QJsonValue(arr);
}
else {
throw "Invalid Value Type";
}
}
Честно говоря, я предпочитаю эту схему, но я знаю, что есть причины для того, чтобы вы пошли тем путем, который вы упомянули, например, чтобы избежать беспричинного выделения памяти.