Виртуальные деструкторы полезны, когда вы можете удалить экземпляр производного класса с помощью указателя на базовый класс:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
};
Здесь вы заметите, что я не объявлял деструктор базы virtual
. Теперь давайте посмотрим на следующий фрагмент:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Поскольку деструктор базы не является virtual
, а b
является Base*
, указывающим на объект Derived
, delete b
имеет неопределенное поведение :
[В
blockquote>delete b
], если статический тип подлежащего удалению объекта отличается от его динамического типа, статический тип должен быть базовый класс динамического типа объекта, подлежащего удалению, и статический тип должен иметь виртуальный деструктор или поведение не определено.В большинстве реализаций вызов деструктора будет разрешен как и любой не виртуальный код, что означает, что деструктор базового класса будет вызываться, но не тот, который был получен из производного класса, что приведет к утечке ресурсов.
Подводя итог, всегда создавайте деструкторы базовых классов
virtual
, когда они предназначены для управления полиморфно.Если вы хотите предотвратить удаление экземпляра с помощью указателя базового класса, вы можете сделать деструктор базового класса защищенным и не виртуальным; при этом компилятор не позволит вам называть
delete
указателем базового класса.Вы можете узнать больше о деструкторе виртуальности и виртуального базового класса в этой статье от Herb Sutter .
Нет другого выбора, кроме рекурсивной обработки json и создания структуры TreeItem
на основе информации элемента.
(Вероятно, есть лучший способ добавить символы, но я не нашел подходящих иконки.)
private static final String INPUT = "{\n"
+ " name:\"tom\",\n"
+ " schools:[\n"
+ " {\n"
+ " name:\"school1\",\n"
+ " tags:[\"maths\",\"english\"]\n"
+ " },\n"
+ " {\n"
+ " name:\"school2\",\n"
+ " tags:[\"english\",\"biological\"]\n"
+ " },\n"
+ " ]\n"
+ "}";
private static final Image JSON_IMAGE = new Image("https://i.stack.imgur.com/1slrh.png");
private static void prependString(TreeItem<Value> item, String string) {
String val = item.getValue().text;
item.getValue().text = (val == null
? string
: string + " : " + val);
}
private enum Type {
OBJECT(new Rectangle2D(45, 52, 16, 18)),
ARRAY(new Rectangle2D(61, 88, 16, 18)),
PROPERTY(new Rectangle2D(31, 13, 16, 18));
private final Rectangle2D viewport;
private Type(Rectangle2D viewport) {
this.viewport = viewport;
}
}
private static final class Value {
private String text;
private final Type type;
public Value(Type type) {
this.type = type;
}
public Value(String text, Type type) {
this.text = text;
this.type = type;
}
}
private static TreeItem<Value> createTree(JsonElement element) {
if (element.isJsonNull()) {
return new TreeItem<>(new Value("null", Type.PROPERTY));
} else if (element.isJsonPrimitive()) {
JsonPrimitive primitive = element.getAsJsonPrimitive();
return new TreeItem<>(new Value(primitive.isString()
? '"' + primitive.getAsString() + '"'
: primitive.getAsString(), Type.PROPERTY));
} else if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray();
TreeItem<Value> item = new TreeItem<>(new Value(Type.ARRAY));
// for (int i = 0, max = Math.min(1, array.size()); i < max; i++) {
for (int i = 0, max = array.size(); i < max; i++) {
TreeItem<Value> child = createTree(array.get(i));
prependString(child, Integer.toString(i));
item.getChildren().add(child);
}
return item;
} else {
JsonObject object = element.getAsJsonObject();
TreeItem<Value> item = new TreeItem<>(new Value(Type.OBJECT));
for (Map.Entry<String, JsonElement> property : object.entrySet()) {
TreeItem<Value> child = createTree(property.getValue());
prependString(child, property.getKey());
item.getChildren().add(child);
}
return item;
}
}
@Override
public void start(Stage primaryStage) {
JsonParser parser = new JsonParser();
JsonElement root = parser.parse(INPUT);
TreeItem<Value> treeRoot = createTree(root);
TreeView<Value> treeView = new TreeView<>(treeRoot);
treeView.setCellFactory(tv -> new TreeCell<Value>() {
private final ImageView imageView;
{
imageView = new ImageView(JSON_IMAGE);
imageView.setFitHeight(18);
imageView.setFitWidth(16);
imageView.setPreserveRatio(true);
setGraphic(imageView);
}
@Override
protected void updateItem(Value item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
imageView.setVisible(false);
} else {
setText(item.text);
imageView.setVisible(true);
imageView.setViewport(item.type.viewport);
}
}
});
final Scene scene = new Scene(treeView);
primaryStage.setScene(scene);
primaryStage.show();
}
Shape
s (Text
/Rectangle
), чтобы не нарушать какие-либо авторские права ... – fabian 26 June 2018 в 12:14TreeCell
. Это новый вопрос, хотя на комментарий нельзя ответить должным образом. – fabian 6 July 2018 в 08:35