Какое свойство строит иерархию объектов

Какое свойство строит иерархию объектов thumbnail

0 / 0 / 0

Регистрация: 10.12.2019

Сообщений: 65

1

01.05.2020, 14:26. Просмотров 1660. Ответов 1

У меня возникла ошибка в main.cpp, строка 12, пишет: «значение типа «cl_base*» нельзя использовать для инициализации сущности типа «cl_base2*» «. Не знаю как это исправить.

Само задание.

Для организации иерархического построения объектов необходимо разработать базовый класс, который содержит функционал и свойства для построения иерархии объектов. В последующем, в приложениях использовать этот класс как базовый для всех создаваемых классов. Это позволит включать любой объект в состав дерева иерархии объектов.

Создать базовый класс со следующими элементами:

Свойства:

— наименование объекта (строкового типа);
— указатель на головной объект для текущего объекта (для корневого объекта значение указателя равно 0);
— список указателей на объекты подчиненных к текущему объекту в дереве иерархии.

Функционал:
— параметризированный конструктор с параметром указателя на головной объект в дереве иерархии;
— параметризированный конструктор с параметром указателя на головной объект в дереве иерархии и наименованием объекта;
— метод задания имени объекта;
— метод получения имени объекта;
— метод вывода наименований объектов в дереве иерархии слева направо и сверху вниз.

Написать программу, которая последовательно строит дерево иерархии объектов, слева направо и сверху вниз. Переход на новый уровень происходит от правого (последнего) объекта предыдущего уровня. Для построения дерева использовать объекты двух производных классов, наследуемых от базового. Каждый объект имеет уникальное имя.

Построчно, по уровням вывести наименования объектов построенного иерархического дерева.

Входные данные

Первая строка:
«имя корневого объекта»
Создается корневой объект.
Вторая строка и последующие строки:
«имя головного объекта» «имя подчиненного объекта»
Создается подчиненный объект и добавляется в иерархическое дерево.

Если «имя головного объекта» равняется «имени подчиненного объекта», то новый объект не создается и построение дерева объектов завершается.

Пример ввода

Object_root
Object_root Object_1
Object_root Object_2
Object_root Object_3
Object_3 Object_4
Object_3 Object_5
Object_6 Object_6

Дерево объектов, которое будет построено по данному примеру:

Object_root
Object_1
Object_2
Object_3
Object_4
Object_5

Выходные данные

Первая строка:
«имя корневого объекта»
Вторая строка и последующие строки имена головного и подчиненных объектов очередного уровня разделенных двумя пробелами.
«имя головного объекта» «имя подчиненного объекта»[[ «имя подчиненного объекта»] …….]

Пример вывода

Object_root
Object_root Object_1 Object_2 Object_3
Object_3 Object_4 Object_5

Это код который я написал.

Osnova.h

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef IRARH_H
#define IRARH_H
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class cl_base
{
private:
    string object_name;
    cl_base* p_parent;
public:
    cl_base(cl_base* p_parent, string s_object_name);
    cl_base(cl_base* p_parent);
    ~cl_base();
    void set_object_name(string s_object_name);
    string get_object_name();
    void showtree();
    vector <cl_base* > children;
    vector <cl_base* >::iterator it_child;
};
 
class cl_base1 :public cl_base
{
public:
    using cl_base::cl_base;
};
class cl_base2 :public cl_base
{
public:
    using cl_base::cl_base;
};
 
#endif

Osnova.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include «Osnova.h»
using namespace std;
 
 
cl_base::cl_base(cl_base* p_parent, string s_object_name)
{
    set_object_name(s_object_name);
    this->p_parent = p_parent;
    if (this->p_parent != 0)
        this->p_parent->children.push_back(this);
}
 
cl_base::cl_base(cl_base* p_parent)
{
    this->p_parent = p_parent;
}
 
cl_base::~cl_base()
{
    for (int i = 0; i < this->children.size(); i++)
    {
        delete this->children[i];
    }
}
 
void cl_base::set_object_name(string s_object_name)
{
    object_name = s_object_name;
}
 
string cl_base::get_object_name()
{
    return object_name;
}
 
void cl_base::showtree()
{
    cout << this->get_object_name();
    for (int i = 0; i < this->children.size(); i++) {
        cout << » » << this->children[i]->get_object_name();
    }
    for (int i = 0; i < this->children.size(); i++) {
        if (this->children[i]->children.size() != 0) {
            cout << endl;
            children[i]->showtree();
        }
    }
}

main.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>
#include «Osnova.h»
 
using namespace std;
 
int main()
{
    string root, parent, name;
    cin >> root;
    cl_base* ob_root = new cl_base(0, root);
    cl_base2* ob = ob_root;
    cl_base2* temp = 0;
    for (int i = 0; ; i++)
    {
        cin >> parent >> name;
        if (parent == name)
            break;
        if (i != 0 && ob->get_object_name() != parent)
            ob = temp;
        temp = new cl_base2(ob, name);
    }
    cout << ob_root->get_object_name() << endl;
    ob_root->showtree();
    delete ob_root;
    delete temp;
    return 0;
}

Источник

1. (60c.) Какое из имен используется для задания текста процедур, функций, методов?
(один ответ)
1) LABEL
2) INTERFACE
3) IMPLEMENTATION
4) VAR

Читайте также:  На каких свойствах воды основано водолечение по кнейпу

2. (60c.) Какая из операций используется для указания остатка?
(один ответ)
1) DIV
2) MOD
3) {$
4) ^

3. Какая из операций используется для указания директив компиллятора?
(один ответ)
1) DIV
2) MOD
3) {$
4) ^

5. (60c.) Какой из типов данных относится к действительным числам?
( один ответ)
1) BOOLEAN
2) CHAR
3) SINGLE
4) CARDINAL

6. (60c.) Какое из описаний типов относится к записи?
( один ответ)
1) Ww=function(X:real):real;
2) Ww=record x,y:real; end;
3) Ww=’a’..’z’
4) Ww=array[1..10] of real;

7. (60c.) Какое из названий обозначает описание типа записи?
( один ответ)
1) property
2) Ww=record x,y:real; end;
3) constructor
4) destructor

8. (60c.) Какое из свойств объекта относится к графическому изображению?
( один ответ)
1) hint
2) set focus
3) canvas
4) items

9. (60c.) Какое из свойств объекта относится к списку строк?
( один ответ)
1) hint
2) set focus
3) canvas
4) items

10. (60c.) Какая из процедур используется для открытия файла для чтения из него?
( один ответ)
1) AssignFile
2) Reset
3) Rewrite
4) Append

11. (60c.) Какая из процедур используется для открытия файла для дозаписи в конец файла?
( один ответ)
1) AssignFile
2) Reset
3) Rewrite
4) Append

12. (60c.) Какая из операций обозначает получение адреса?
(один ответ)
1) @
2) +
3) ^
4) *

13. (60c.) Какая из операций используется при описании типа указателя?
(один ответ)
1) @
2) +
3) ^
4) *

14. (60c.) Какая связка операторов обозначает цикл c выходом по условию?
(один ответ)
1) For…to…do
2) If…then…else
3) Case…of… end
4) While…do

1 5. (60c.) Какая связка операторов дает выбор из 3-х и более вариантов?
(один ответ)
1) For…to…do
2) If…then…else
3) Case…of… end
4) While…do

1 6. (60c.) Какая из процедур имеет только типизированные параметры-переменные?
( один ответ)
1) procedure si(var x,y:real);
2) procedure si(x,y:real);
3) procedure si(var x,y) ;
4) procedure si(x:real;var y):real;

17. (60c.) Укажите правильное описание переменной строкового типа.
( один ответ)
1) a:array[1..10] of real;
2) a:string[10];
3) a:set of (1,10);
4) a:record n:real; f:real; end;

18. (60c.) Какой из терминов обозначает окно модуля формы?
( один ответ)
1) Object Inspector
2) Database Desktop
3) Paradox
4) Unit

19. (60c.) Какой из терминов обозначает свойство заголовка объекта?
( один ответ)
1) Canvas
2) Events
3) Caption
4) Enabled

20. (60c.) Какой из терминов обозначает свойство логического типа?
( один ответ)
1) Canvas
2) Events
3) AlClient
4) Enabled

21. (60c.) Какая из структур имеет нумерацию элементов?
(один ответ)
1) Очередь
2) Стек
3) Двусвязный список
4) Массив

22. (60c.) Вызов функцией самой себя это -…
(один ответ)
1) Рекурсия
2) Итерация
3) Процедура
4) Динамическая структура

23. (60c.) Какое расширение имеют файлы модулей в DELPHI?
(один ответ)
1) *.exe
2) *.com
3) *.dpr
4) *.pas

24. (60c.) Какое из свойств использует виртуальные или перегружаемые элементы?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Объектно-Ориентированные

25. (60c.) Какое из имен используется как заголовок файла проекта?
(один ответ)
1) PROGRAM
2) USES
3) UNIT
4) TYPE

26. (60c.) Какое из имен используется для описания классов проекта или модуля?
(один ответ)
1) PROGRAM
2) USES
3) UNIT
4) TYPE

27. (60c.) Какой из терминов обозначает окно модуля формы?
( один ответ)
1) Object Inspector
2) Database Desktop
3) Paradox
4) Unit

28. (60c.) Какой из терминов обозначает свойство заголовка объекта?
( один ответ)
1) Canvas
2) Events
3) Caption
4) Enabled

29. (60c.) Какой из терминов обозначает свойство логического типа?
( один ответ)
1) Canvas
2) Events
3) AlClient
4) Enabled

30. (60c.) Какой из терминов обозначает константу для свойства размещения?
( один ответ)
1) Canvas
2) LineTo
3) AlClient
4) Enabled

31. (60c.) Какое из свойств обозначает выбор шрифта?
( один ответ)
1) Font
2) Pen
3) Image
4) Alias

32. (60c.) Какое из свойств скрывает внутренние данные объекта?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Объектно-Ориентированные

33. (60c.) Какое из свойств предназначено для улучшения интерфейса работы с объектами?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Визуальность

34. (60c.) Какая из операций используется для указания директив компилятора?
(один ответ)
1) DIV
2) MOD
3) {$
4) ^

35. (60c.) Какая из операций используется для определения указателя?
(один ответ)
1) DIV
2) MOD
3) {$
4) ^

36. (60c.) Какая из операций обозначает получение адреса?
(один ответ)
1) @
2) +
3) ^
4) *

37. (60c.) Какая из структур имеет нумерацию элементов?
(один ответ)
1) Очередь
2) Стек
3) Двусвязный список
4) Массив

38. (60c.) Какое из названий обозначает доступные только потомкам элементы класса?
(один ответ)
1) public
2) published
3) protected
4) private

39. (60c.) Какое из разделов класса выбирается по умолчанию?
(один ответ)
1) public
2) published
3) protected
4) private

40. (60c.) Какое из свойств не является принципом объектно ориентированного программирования?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Визуальность

41. (60c.) Какое из свойств определяет скрытие полей объектов?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Визуальность

42. (60c.) Какое из свойств может быть связано с переопределением методов объектами?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Визуальность

Читайте также:  Какие свойства у травы чабрец

43. (60c.) Какое из свойств предназначено для передачи всех свойств от класса к классу?
(один ответ)
1) Инкапсуляция
2) Полиморфизм
3) Наследование
4) Визуальность

44. (60c.) Какой из терминов может относиться к термину OnClick?
(один ответ)
1) Конструктор
2) Деструктор
3) Свойство
4) Событие

 Комментарий модератора 
Это, конечно, очень хорошо, что Вы стараетесь приукрасить всё, что можно, но большое количество цветного текста жирными буквами плохо читается. Не нужно так делать.

 Комментарий модератора 
Многие вопросы сформулированы некорректно. Даже — неграмотно. Если не секрет — что за учебное заведение, где такие тесты готовят?

Источник

Доброго времени суток. Представлюсь, для тех, кто меня еще не знает. Меня зовут Дима. Я работаю C++ разработчиком уже более 5-ти лет. На данный момент работаю в крупной Gamedev-студии. Помимо работы увлекаюсь созданием образовательного контента для YouTube и Twitch каналов.

С++. Какой же противоречивый язык программирования. Выбираете за совместимость с Си – получаете утечки памяти, хотите высокую производительность – получаете огромное время компиляции, хотите шаблоны и метапрограммирование – получаете отладку, больше похожую на ходьбу по минному полю, где вместо взрыва – исправление в хидере(да, реализация шаблонов только в хидер-файлах и последствия этого — вообще отдельная тема для разговора) и ожидание компиляции, когда чувствуешь, что умираешь от старости. Я сделал для себя такие выводы: C++ – отличный язык программирования. Язык, который хочет включить себя всё, от простоты, а скорее сложности си, до сложности, или простоты современных мультипарадигменных языков программирования.

Что же, Вы выбрали C++ и вы не хотите бороться с утечками памяти? Ответ на первый взгляд прост – умные указатели. Но, ведь тут тоже не так всё просто, вы не хотите получить частые обращение к куче, которые сами по себе очень недешёвые (системный вызов, синхронизация), и вы не хотите в итоге получить излишнюю фрагментацию вашей памяти. Ответ тут тоже есть. Статическая иерархия объектов вашей программы. Под этим я подразумеваю, что ваша программа создаст необходимые ей объекты на момент запуска и удалит их в момент завершения своего выполнения. Увы, но тут тоже не всё так просто ибо подобный подход подходит (да-да, тавтология-повторение) для определённого класса задач. Приведу наглядные примеры, дабы было понятнее.

Геймдев. Игры жанра Match3. На момент запуска этого приложения Вы уже знаете, что Вам от него нужно. Главное меню, уровень. Уровень может конфигурироваться файлами с вашего диска или информацией с сервера, но вы уже знаете все объекты, которые вам нужно создать. Соответственно, не нужно думать, что и в какой момент выделить, что и когда удалить. Всё, что вам нужно, – правильное отображение информации. Можно привести в пример даже AAA-игры. Запускаем очередную версию Battlefield и видим, что, отображая только главное меню, игра уже выделила 4 Гб оперативной памяти. Подозрительно? Да нет, не очень. Очевидно, что разработчики следовали тому же принципу.

Симуляция. Мне приходилось работать с программными продуктами, назначение которых – симулировать процессы, происходящие на железе. ТО есть симулировать некий микроконтроллер или нечто более сложное. Жёсткий диск, процессор. Зачем это нужно? Для тестирования прошивки железа или драйверов, когда самого железа еще не существует, или устройств слишком мало, чтобы дать возможность тестировать его достаточному количеству разработчиков прошивки. По сути, винчестер не изменится в процессе работы, в нём не станет больше памяти или один контроллер вдруг не заменит другой. Соответственно, имеет смысл создать все объекты сразу на момент запуска теста и удалить их на момент его завершения.

Далее всё довольно просто. Вы создаёте некий главный объект. Например, Game. В его полях вы создаёте объекты MainMenu, Level, ScoreBoard, NetworkManager… В их полях создаёте другие объекты и так далее. Всё вроде бы хорошо. Однако ваша архитектура усложняется, вам необходимы какие-то общие методы, всё-таки у нас тут ООП и полиморфизм, например, вызов какой-то логики у объекта, каждый кадр, тот, кто работал с игровыми движками, понимает. Или же, как минимум, объектам понадобятся общие методы для поиска друг друга. И тут возникает проблема, ибо нужно все объекты объединить в некую абстрактную иерархию базовых объектов.

Я сталкивался с решениями, когда для объектов дочерних (не в смысле наследников, а в смысле полей класса) нужно вызвать что-то типа add_child и добавлять этот вызов самостоятельно для каждого созданного объекта. Мне кажется, что это чересчур опасное решение с точки зрения вероятности упустить добавление объекта, особенно человеку, который не знаком с правилами.

Цель

Мы хотим иметь возможность создавать такой класс, в поля которого можно добавить объекты, которые будут объединены в иерархию базовых классов.

class Game
{
public:
Player _player;
Enemy _enemy;
}

В приведённом примере мы хотим иметь возможность обратится к полям _player или _enemy класса Game через некий массив указателей _children;

Решение

Очевидно, что нам понадобится некий базовый класс:

class BaseNode
{
public:
BaseNode(const std::string& name);

protected:
//Добавим каждому объекту возможность идентифицировать себя
std::string _name;
std::vector<BaseNode*> _children;
};

Далее разберёмся с порядком вызова конструкторов. Порядок вызова конструкторов довольно прост. Порядок вызова = порядок объявления.
Продемонстрирую на примере:

class Base {};

class Field : public Base {};

class Child : public Base
{
Field _field1;
Field _field2;
};

  • Base() — класс Child
  • Base() — поле _field1
  • Fileld() — поле _field1
  • Base() — поле _field2
  • Fileld() — поле _field2
  • Child() — класс Child
Читайте также:  Какие свойства биосферы позволяют назвать ее экосистемой

Обратимся к написанному ранее классу BaseNode. По сути будет всегда запускаться следующая цепочка. BaseNode контейнера, BaseNode полей, конструкторы полей, конструктор контейнера. Здесь уже можно обратить внимание, что это всё напоминает поиск в глубину.

Создадим глобальный стек.

namespace
{
std::stack<BaseNode*> stack;
}

BaseNode::BaseNode(const std::string& name)
: _name(name.)
{
if (!stack.empty())
{
//на вершине стека находится объект-контейнер текущего объекта
stack.top()->_children.push_back(this);
}
//Добавляем себя на вершину стека
stack.push(this);
}

Данное решение сработает, если у нас есть один класс контейнер, который в себе хранит одно поле. Ведь на данный момент нет удаления с вершины стека в нужный момент. Обратимся к примеру с порядком вызова и укажем место, где именно нужно удалять с вершины стека

  • Base() — класс Child
  • Base() — поле _field1
  • Fileld() — поле _field1. В этой точке уже известно, что детей у field1 больше нет и мы можем удалять его с вершины стека.

Чтобы добиться нормального удаления объекта с вершины стека, не добавляя удаление в каждый новый конструктор, вместо const std::string& name в конструкторе нашего класса будем использовать свой собственный временный объект, который будет отвечать за индикацию классов по имени.

struct NodeName
{
NodeName(const char* name);
NodeName(const std::string& name);
~NodeName();

std::string _name;
};

Каким будет время жизни данного объекта? Мы по-прежнему будем объявлять его в конструкторах через константную ссылку, ибо объявление по значению для объектов, которые больше по своему размеру, чем системное слово, как-то некрасиво. Но, по сути, нам нужен именно такой объект, дабы добиться его времени жизни только на тот момент, пока мы находимся в цепочке конструкторов объекта-контейнера. То есть «пытаясь» вызвать конструктор контейнера, мы попадём в базовый конструктор, затем конструкторы детей, а потом уже в конструктор контейнера, по выходу из которого NodeName и будет уничтожен. Получается, что удалять объект с вершины глобального стека нужно как раз на разрушении очередного объекта класса NodeName. Перейдём, наконец, к полной реализации.

// BaseNode.h
#pragma once

#include <string>
#include <vector>

#define NODE_DECL(obj) obj{#obj}

struct NodeName
{
NodeName(const char* name);
NodeName(const std::string& name);
~NodeName();

std::string _name;
};

class BaseNode
{
public:
BaseNode(const NodeName& name);

protected:
std::string _name;
std::vector<BaseNode*> _children;
};
//////////////////////////////////////////////////

//BaseNode.cpp
#include «BaseNode.h»

#include <iostream>
#include <stack>

namespace
{
std::stack<BaseNode*> stack;
}

BaseNode::BaseNode(const NodeName& name)
: _name(name._name)
{
if (!stack.empty())
{
//Обратились к вершине стека и добавили туда себя в качестве ребёнка
stack.top()->_children.push_back(this);
}
// Добавили себя на вершину стека
stack.push(this);
}

//Два конструктора для более удобной работы
NodeName::NodeName(const char* name)
: _name(name) {}

NodeName::NodeName(const std::string& name)
: _name(name) {}

NodeName::~NodeName()
{
//Снимаем объект BaseNode с вершины стека
stack.pop();
}

Можно обратить внимание, что в удалении объекта нет проверки на то, что стек не пуст. Это сделано нарочно, ведь если стек окажется не пуст, значит кто-то построил иерархию неверно и приложение упадёт на этапе инициализации.

#define NODE_DECL(obj) obj{#obj}

Данный макрос будем использовать для инициализации полей классов в нашей иерархии, чтобы создавать NodeName с помощью строкового литерала, то есть приводя к созданию временного объекта. Плюс получится довольно удобно, что имя объекта в иерархии будет равно имени переменной в коде. Продемонстрирую применение на примере:

#include <iostream>
#include «BaseNode.h»

// Все классы должны быть наследниками BaseNode
class C : public BaseNode
{
public:
C(const NodeName& name)
: BaseNode(name) {}
};

//Данный класс будет хранить один дочерний объект в иерархии
class A : public BaseNode
{
public:
A(const NodeName& name)
: BaseNode(name) {}
private:
//Дочерний объект имя дочернего объекта будет «_c»
C NODE_DECL(_c);
};

//Данный класс будет хранить один дочерний объект в иерархии
class B : public BaseNode
{
public:
B(const NodeName& name)
: BaseNode(name) {}
private:
//Дочерний объект
C NODE_DECL(_c);
};

//Главный класс, который хранит два дочерних объекта классов A B
class Parent : public BaseNode
{
public:
Parent(const NodeName& name)
: BaseNode(name) {}

private:
A NODE_DECL(_a);
B NODE_DECL(_b);
};

int main()
{
//Объявим данный объект на стека
//По заверешнию выполнения функции мэйн он будет удалён
//В случае с большим объектами можно создать его на куче
//И удалить по заверешнию работы программы
Parent NODE_DECL(parent);
return 0;
}

В итоге, следует выполнять два пункта для работы нашей иерархии:

  • Наследование от базового класса
  • Правильное объявление переменных (для стандартизации предлагаю пользоваться подобными макросами).

Каждый раз объявлять конструктор и вызывать конструктор базового класса тоже выглядит довольно-таки громоздко. Для ускорения можно использовать оператор using:

// Без using
class C : public BaseNode
{
public:
C(const NodeName& name)
: BaseNode(name) {}
};

//Иcпользуя using
class A : public BaseNode
{
public:
using BaseNode::BaseNode;
};

Заключение

Прелесть данного решения в том, что технический долг, которого нужно придерживаться, создавая новые объекты в иерархии, крайне мал. Также присутствует защита, которая тут же сообщит разработчику-пользователю, что он объявляет объекты в иерархии неверно. Речь об удалении объекта с вершины стека, без проверки на его пустоту.
Задавайте в комментариях вопросы. Пишите, если увидите какие-то ошибки, и спасибо за внимание.

Для полной картины и объяснения в формате видео предлагаю ознакомиться с записью стрима, где я реализую код из статьи и объясняю всё максимально подробно:

Мы на других ресурсах

{
«author_name»: «Ambushed Raccoon»,
«author_type»: «self»,
«tags»: [«pragma»,»obj»,»include»,»define»],
«comments»: 35,
«likes»: 50,
«favorites»: 221,
«is_advertisement»: false,
«subsite_label»: «gamedev»,
«id»: 126148,
«is_wide»: false,
«is_ugc»: true,
«date»: «Sun, 19 Apr 2020 11:55:39 +0300»,
«is_special»: false }

Источник