Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.76/34: Рейтинг темы: голосов - 34, средняя оценка - 4.76
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614

Создание игр в текстовом режиме

17.02.2014, 00:43. Показов 8175. Ответов 67
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем! Тут занялся написанием игрушек в текстовом режиме, типа змейки, тетриса и т.п. Суть в том, что я хочу как можно более правильно написать код, со стороны рефакторинга, со стороны выделения и освобождения памяти, и многих других аспектов. Думаю эта тема поможет многим новичкам, в написание чего-либо подобного, поэтому буду потихоньку выкладывать свои исходники и ждать ваших комментариев.Долго думал куда все-таки отнести эту тему, но решил остановиться здесь.
Итак, сейчас я хочу выложить класс интерфейса(менюшка), и данный класс будет использоваться в любой мной написанной игре.

Файл _interface.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
35
36
37
38
39
40
41
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include "msoftcon.h"
using namespace std;
 
 
/* ## Cтруктура списка интерфейса ## */
struct ListMenu 
{
    vector<wstring> item;
};
 
 
/* ## Абстрактный класс интерфейса ## */
class _interface
{
protected:
    int CurrentMenu();                              // Получение текущего списка меню
    int CurrentCursor();                            // Получение каретки текущего пункта меню
    static void NextMenu();                         // Следующий список меню
    static void BackMenu();                         // Предыдущий список меню
    void AddListMenu(wstring);                      // Добавить пункт в список меню
    void ClearListMenu();                           // Очистить список меню
    int SizeListMenu();                             // Размер списка меню
    void DrawMenu();                                // Прорисовка списка меню
 
private:
    static int current_menu;                        // Текущий список меню
    int current_cursor;                             // Каретка текущего пункта меню
    int x,y;                                        // Координаты прорисовки списка на экране
    ListMenu *menu;                                 // Структура списка меню
 
public:
    _interface(int,int);                            // Конструктор
    ~_interface();                                  // Деструктор
 
    virtual void Run() = 0;                         // Запуск статической системы меню
    virtual void Run(ListMenu*) = 0;                // Запуск динамической системы меню
};
Ну что могу сказать по поводу этого класса. Ну первое, это абстрактный класс, то есть создание экземпляров от этого класса будет невозможно.

У меня есть 8 методов в области видимости protected, которые будут доступны соответственно классу - потомку. Сейчас распишу примерно, что каждый метод делает:
Кликните здесь для просмотра всего текста
int CurrentMenu() - Соответственно получает номер текущего меню. При создании первого экземпляра класса - потомка номер текущего меню равен 0.
static void NextMenu() - Изменяет номер текущего меню на следущее +1.
static void BackMenu(); - Изменяет номер текущего меню на предыдущее -1.
int CurrentCursor() - Получаем номер текущего пункта меню, где в данное время находится каретка указателя.
void AddListMenu(wstring) - Так мы можем добавить пункт меню в список меню.
void ClearListMenu() - Соответсвенно, что видно из название - очищаем список меню.
int SizeListMenu() - Размер текущего списка меню(Количество пунктов меню данного списка).
void DrawMenu() - Метод прорисовки списка меню и выбора определенного пункта меню.


Теперь расскажу про область видимости private. Там находятся поля класса. Про них особо нечего рассказывать, практически все методы, которые были описаны выше, просто манипулируют этими полями и все:
Кликните здесь для просмотра всего текста
static int current_menu - Номер текущего меню. Причем сколько бы экземпляров класса - потомка не было, это значение для всех общее.
int current_cursor - Номер текущего пункта меню, где в данное время находится каретка указателя.
int x,y - Координаты вывода списка меню на экране.
ListMenu *menu - Ну и конечно структура самого списка меню, состоящая из одного всего поля - вектора библиотеки STL, где хранятся все пункты меню.


Ну и public:
Кликните здесь для просмотра всего текста
_interface(int,int) - Конструктор как вы поняли.
~_interface() - Деструктор соответственно.
virtual void Run() = 0 - Вот это самое интересное.Это чисто виртуальная функция, которая будет заводить всю систему меню. Она должна обязательно быть перегружена в классе - потомке, и все меню и события по нажатию на определенные пункты меню должны создаваться в ней. То есть все что связано с меню, должно выполняться именно в этой функции.
virtual void Run(ListMenu*) = 0 - Метод Run(), это статическое управление списками меню, то есть я не могу создавать, изменять, удалять меню программно. Для этого я создал функцию Run(ListMenu*), которая делает все тоже самое что и Run(), только принимает в качестве формального параметра список меню, что следовательно,что я могу создать меню программно, что иногда очень бывает нужно.


Выкладываю определение всех методов данного класса. Файл _interface.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "_interface.h"
 
 
int _interface :: current_menu = 0;
 
 
/* ## Конструктор ## */
_interface :: _interface(int x1,int y1) : x(x1),y(y1)
{ 
    init_graphics();
    menu = new ListMenu;
}
 
 
/* ## Деструктор ## */
_interface :: ~_interface()
{ }
 
 
/* ## Следующий список меню ## */
void _interface :: NextMenu()
{
    current_menu++;
}
 
 
/* ## Предыдущий список меню ## */
void _interface :: BackMenu()
{
    current_menu--;
}
 
 
/* ## Получение текущего списка меню ## */
int _interface :: CurrentMenu()
{
    return current_menu;
}
 
 
/* ## Получение каретки текущего пункта меню ## */
int _interface :: CurrentCursor()
{
    return current_cursor;
}
 
 
/* ## Добавить пункт в список меню ## */
void _interface :: AddListMenu(wstring item)
{
    menu -> item.push_back(item);
}
 
 
/* ## Очистить список меню ## */
void _interface :: ClearListMenu()
{
    menu -> item.clear();
}
 
 
/* ## Размер списка меню ## */
int _interface :: SizeListMenu()
{
    return menu -> item.size();
}
 
 
/* ## Прорисовка списка меню ## */
void _interface :: DrawMenu()
{
    set_color(cWHITE,cBLACK);
    clear_screen();
 
    for(int i = 0; i < menu -> item.size(); i++)
    {
        set_cursor_pos(x + 4,y + i);
        wcout << menu -> item[i] << endl;
    }
 
    set_cursor_pos(x,y);
    current_cursor = 1;
    char c;
 
    do
    {
        for(int i = 0; i < SizeListMenu(); i++)
        {
            if(i == current_cursor - 1)
            { set_color(cBLACK,cYELLOW); }
            else
            { set_color(cBLACK,cBLUE); }
 
            set_cursor_pos(x,y + i);
            cout << "->";
        }
 
        c = _getch();
 
        switch(c)
        {
        case 72: if(current_cursor != 1) { current_cursor = current_cursor - 1; } break;
        case 80: if(current_cursor != SizeListMenu()) { current_cursor = current_cursor + 1; } break;
        }
    }
    while(c != 13);
}
Ну если все понятно, можно теперь создать собственно меню.) Создаем вначале класс - потомок. Файл ___interface.h

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
#include "_interface.h"
using namespace std;
 
 
/* ## Производный класс от класса интерфейса ## */
class ___interface : public _interface
{
public:
    ___interface(int,int);      // Конструктор
    ~___interface();            // Деструктор
 
    void Run();                 // Запуск статической системы меню
    void Run(ListMenu*);        // Запуск динамической системы меню
};
Здесь вроде все понятно, теперь соответственно определяем функции Run() и Run(ListMenu*). Но прежде чем их определить, нужно придумать меню).
Давайте создадим меню из списка: START, OPTION, EXIT.
По нажатию на START - Выводится сообщение "hello world"
По нажатию на OPTION - Создается второе меню - DINAMIC CREATE MENU, MESSAGE, BACK
По нажатию на EXIT - Выходим из программы

Теперь распишем что будет делать второе меню,созданное по нажатию на OPTION.
По нажатию на DINAMIC CREATE MENU - Создается динамическое меню, из 6 пунктов, если нажмем на один из первых трех - вернемся назад на второе меню, если нажмем на один из трех следующих - вернемся на START, ...
По нажатию на MESSAGE - Выводится сообщение "I Love CyberForum" и возвращаемся на меню START, ...
По нажатию на BACK - Возвращаемся назад на первое меню

Ну вот более менее подходящее меню, чтобы задействовать всю мощь моего написанного класса)
Реализовываем. Файл ___interface.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "___interface.h"
 
 
/* ## Конструктор ## */
___interface :: ___interface(int x,int y) : _interface(x,y)
{ }
 
 
/* ## Деструктор ## */
___interface :: ~___interface()
{ }
 
 
/* ## Запуск системы ## */
void ___interface :: Run()
{
    set_color(cWHITE,cBLACK);
 
    ClearListMenu();
 
    switch(CurrentMenu())
    {
    case 0: // Первое меню - START  OPTION  EXIT
        {
            AddListMenu(L"START");
            AddListMenu(L"OPTION");
            AddListMenu(L"EXIT");
 
            DrawMenu();
 
            switch(CurrentCursor())
            {
            case 1:
                {
                    clear_screen();
                    cout << "hello world";
                    getch();
                }
            break;
 
            case 2:
                {
                    NextMenu();
                }
            break;
 
            case 3:
                {
                    exit(0);
                }
            break;
            }
        }
    break;
 
    case 1: // Второе меню - DINAMIC CREATE MENU   MESSAGE   BACK
        {
            AddListMenu(L"DINAMIC CREATE MENU");
            AddListMenu(L"MESSAGE");
            AddListMenu(L"BACK");
 
            DrawMenu();
 
            switch(CurrentCursor())
            {
            case 1:
                {
                    clear_screen();
                    ListMenu* DinamicMenu = new ListMenu;
                    wstring item;
 
                    for(int i = 0; i < 6; i++)
                    {
                        cout << "Input item of menu";
                        wcin >> item;
                        DinamicMenu -> item.push_back(item);
                    }
 
                    Run(DinamicMenu); // Создаем новое меню динамически
                }
            break;
 
            case 2:
                {
                    clear_screen();
                    cout << "I Love CyberForum";
                    getch();
                    BackMenu();
                }
            break;
 
            case 3:
                {
                    BackMenu();
                }
            break;
            }
        }
    break;
 
    }
 
    Run(); // Рекурсивно вызываем эту же функцию
}
 
 
void ___interface::Run(ListMenu *list)
{
    set_color(cWHITE,cBLACK);
    NextMenu();
    ClearListMenu();                                // Очищаем список
 
    for(int i = 0; i < list -> item.size(); i++)
    {
        AddListMenu(list -> item[i]);               // Инициализируем список с формальным параметром
    }
 
    DrawMenu();                                     // Прорисовка списка меню
 
    switch(CurrentCursor())
    {
    case 1: BackMenu(); break;
    case 2: BackMenu(); break;
    case 3: BackMenu(); break;
    case 4: { BackMenu(); BackMenu(); } break;
    case 5: { BackMenu(); BackMenu(); } break;
    case 6: { BackMenu(); BackMenu(); } break;
    }
}
В main.cpp можно вызвать меню таким способом:

C++
1
2
3
4
5
6
7
8
9
#include "___interface.h"
 
 
void main()
{
    ___interface *inter = new ___interface(38,10);
 
    inter -> Run();
}
Постепенно я буду выкладывать и остальные части игр, и буду слушать ваше мнение по написанному. Почему я начал с меню? Потому что это главный класс, который заводит всю игру, и его нужно написать на сколько можно правильно. Поэтому жду ваших комментариев,критик по поводу написанного, может что то нужно изменить, добавить, убрать. Я прислушаюсь к любому мнению)
1
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
17.02.2014, 00:43
Ответы с готовыми решениями:

Создание интерфейса пользователя в текстовом режиме
Создание интерфейса пользователя в текстовом режиме. Библиотека PDCurses. (С++) Задание: В текстовом режиме экрана реализуйте...

Работа с экраном в текстовом режиме
Ниже дана программа которая до нажатия Esc повторяет действия: случайным образом выбирает размеры (соотношение 25х80) и положение окна ...

Работа с экраном в текстовом режиме
В меню с выбором пунктов Функциональными Клавишами по программе с клавиатуры в 1-е окно вводится текст с цифрами. Во 2-м окне...

67
22.02.2014, 00:49
Студворк — интернет-сервис помощи студентам

Не по теме:

Цитата Сообщение от Bretbas Посмотреть сообщение
еще будут мнения или на этом остановимся?
Говорят, что утро вечера мудренее. Половина России, Украина, Белорусия, Казахстан и др. уже спят.

0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
23.02.2014, 00:42  [ТС]
Так, наконец нашел время все поправить в лучшую сторону. По вашим комментарием собрал вот это:

Файл Interface.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
35
36
37
38
39
40
41
42
43
44
45
#ifndef INTERFACE_H_
#define INTERFACE_H_
 
#include <iostream>
#include <vector>
#include <string>
 
#include "msoftcon.h"
 
 
/* ## Cтруктура списка интерфейса ## */
struct ListMenu 
{
    vector<wstring> item;
};
 
 
/* ## Абстрактный класс интерфейса ## */
class Interface
{
protected:
    int current_menu() const;                       // Получение текущего списка меню
    int current_cursor() const;                     // Получение каретки текущего пункта меню
    static void next_menu();                        // Следующий список меню
    static void back_menu();                        // Предыдущий список меню
    void add_list_menu(wstring);                    // Добавить пункт в список меню
    void clear_list_menu();                         // Очистить список меню
    int size_list_menu() const;                         // Размер списка меню
    void draw_menu();                               // Прорисовка списка меню
 
private:
    static int number_current_menu_;                // Текущий список меню
    int current_cursor_;                            // Каретка текущего пункта меню
    int x_, y_;                                     // Координаты прорисовки списка на экране
    static ListMenu *menu_;                         // Структура списка меню
 
public:
    Interface(int,int);                             // Конструктор
    virtual ~Interface() = 0;                       // Деструктор
 
    virtual void run() = 0;                         // Запуск статической системы меню
    virtual void run(ListMenu*) = 0;                // Запуск динамической системы меню
};
 
#endif  INTERFACE_H_

Файл Inteface.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "Interface.h"
 
 
int Interface :: number_current_menu_ = 1;
ListMenu* Interface :: menu_ = NULL;
 
 
/* ## Конструктор ## */
Interface :: Interface(int x,int y) : x_(x),y_(y)
{ 
    init_graphics();
    menu_ = new ListMenu;
}
 
 
/* ## Деструктор ## */
Interface :: ~Interface()
{ 
    delete menu_;
}
 
 
/* ## Следующий список меню ## */
void Interface :: next_menu()
{
    number_current_menu_++;
}
 
 
/* ## Предыдущий список меню ## */
void Interface :: back_menu()
{
    number_current_menu_--;
}
 
 
/* ## Получение текущего списка меню ## */
int Interface :: current_menu() const
{
    return number_current_menu_;
}
 
 
/* ## Получение каретки текущего пункта меню ## */
int Interface :: current_cursor() const
{
    return current_cursor_;
}
 
 
/* ## Добавить пункт в список меню ## */
void Interface :: add_list_menu(wstring item)
{
    menu_ -> item.push_back(item);
}
 
 
/* ## Очистить список меню ## */
void Interface :: clear_list_menu()
{
    menu_ -> item.clear();
}
 
 
/* ## Размер списка меню ## */
int Interface :: size_list_menu() const
{
    return menu_ -> item.size();
}
 
 
/* ## Прорисовка списка меню ## */
void Interface :: draw_menu()
{
    if ( (menu_ == nullptr) || (menu_ -> item.empty()) )
    {
        clear_screen();
        cout << "Check your list menu!It is empty!";
        _getch();
        exit(0);
    }
 
    set_color(cWHITE,cBLACK);
    clear_screen();
 
    for(unsigned int i = 0; i < menu_ -> item.size(); i++) 
    {
        set_cursor_pos(x_ + 4,y_ + i);
        wcout << menu_ -> item[i] << endl;
    }
 
    set_cursor_pos(x_,y_);
    current_cursor_ = 1;
    char c;
 
    do
    {
        for(int i = 0; i < size_list_menu(); i++)
        {
            if(i == current_cursor_ - 1)
            { set_color(cBLACK,cYELLOW); }
            else
            { set_color(cBLACK,cBLUE); }
 
            set_cursor_pos(x_,y_ + i);
            cout << "->";
        }
 
        c = _getch();
 
        switch(c)
        {
        case 72: if(current_cursor_ != 1) { current_cursor_--; } break;
        case 80: if(current_cursor_ != size_list_menu()) { current_cursor_++; } break;
        }
    }
    while(c != 13);
 
    clear_list_menu();
}
 
 
/* ## Запуск динамической системы меню ## */
void Interface :: run(ListMenu *list)
{
    if ( (list == nullptr) || (list -> item.empty()) )
    {
        clear_screen();
        cout << "Check your list menu!It is empty!";
        _getch();
        exit(0);
    }
}

Файл InterfaceChild.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef INTERFACECHILD_H_
#define INTERFACECHILD_H_
 
#include "Interface.h"
 
 
/* ## Производный класс от класса интерфейса ## */
class InterfaceChild : public Interface
{
public:
    InterfaceChild(int,int);        // Конструктор
    ~InterfaceChild();              // Деструктор
 
    void run();                     // Запуск статической системы меню
    void run(ListMenu*);            // Запуск динамической системы меню
};
 
#endif INTERFACECHILD_H_

Файл InterfaceChild.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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "InterfaceChild.h"
 
 
/* ## Конструктор ## */
InterfaceChild :: InterfaceChild(int x,int y) : Interface(x,y)
{ }
 
 
/* ## Деструктор ## */
InterfaceChild :: ~InterfaceChild()
{ }
 
 
/* ## Запуск системы ## */
void InterfaceChild :: run()
{
    set_color(cWHITE,cBLACK);
 
    switch(current_menu())
    {
    case 1: // Первое меню - START  OPTION  EXIT
        {
            add_list_menu(L"START");
            add_list_menu(L"OPTION");
            add_list_menu(L"EXIT");
 
            draw_menu();
 
            switch(current_cursor())
            {
            case 1:
                {
                    clear_screen();
                    cout << "hello world";
                    _getch();
                }
            break;
 
            case 2:
                {
                    next_menu();
                }
            break;
 
            case 3:
                {
                    exit(0);
                }
            break;
            }
        }
    break;
 
    case 2: // Второе меню - DINAMIC CREATE MENU   MESSAGE   BACK
        {
            add_list_menu(L"DINAMIC CREATE MENU");
            add_list_menu(L"MESSAGE");
            add_list_menu(L"BACK");
 
            draw_menu();
 
            switch(current_cursor())
            {
            case 1:
                {
                    clear_screen();
                    ListMenu* DinamicMenu = new ListMenu;
                    wstring item;
 
                    for(int i = 0; i < 6; i++)
                    {
                        cout << "Input item of menu";
                        wcin >> item;
                        DinamicMenu -> item.push_back(item);
                    }
 
                    run(DinamicMenu);
                }
            break;
 
            case 2:
                {
                    clear_screen();
                    cout << "I Love CyberForum";
                    _getch();
                    back_menu();
                }
            break;
 
            case 3:
                {
                    back_menu();
                }
            break;
            }
        }
    break;
 
    }
 
    run(); // Рекурсивно вызываем эту же функцию
}
 
 
void InterfaceChild :: run(ListMenu *list)
{
    Interface :: run(list);
    set_color(cWHITE,cBLACK);
 
    for(unsigned int i = 0; i < list -> item.size(); i++)
    {
        add_list_menu(list -> item[i]);                 // Инициализируем список с формальным параметром
    }
 
    draw_menu();                                        // Прорисовка списка меню
 
    switch(current_cursor())
    {
    case 1: back_menu(); break;
    case 2: back_menu(); break;
    case 3: back_menu(); break;
    }
}

Ну и конечно же сам main.cpp
C++
1
2
3
4
5
6
7
8
9
10
#include "InterfaceChild.h"
 
 
int main()
{
    InterfaceChild *inter = new InterfaceChild(38,10);
    inter -> run();
 
    return 0;
}

Вроде все, ничего не забыл) Ну теперь жду ваших новых комментариев по новому "улучшенному коду". Что скажете? Так оставлять или можно что-то еще изменить?)
0
Антикодер
Эксперт функциональных языков программирования
1889 / 871 / 48
Регистрация: 15.09.2012
Сообщений: 3,092
23.02.2014, 01:11
Название класса Interface не несёт в себе никакой сущности, вы также не определяете пространств имен для класса.
В больших проектах это грозит тем, что на использование класса Interface будут претендовать совершенно разные по назначению классы, и в конечном счете заставит разделить вас класс Interface на несколько. Этой ситуации можно избежать, определив на ранних этапах сущности предметной области, что я и пытался объяснить в статье на которую давал ссылку. Думаю Страуструп также относит ваш подход к "overabstract"

Поэтому дальше названия класса проверять не интересно.
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
23.02.2014, 01:29  [ТС]
XRuZzz, я не понял, какой сущности нет в названии моего класса?Если я переименую его в AbstractInterface то будет у него сущность?или я вас не правильно понял?объясните пожалуйста.
а про какие пространства имен идет речь?у меня в классе используется только одно пространство имен std и больше ничего.
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
23.02.2014, 08:24
Для такой простой задачи написать такой сложный класс - это, конечно, надо было постараться.
Не будем зарываться в реализацию, а посмотрим на класс с точки зрения пользователя.

По идее, должно быть достаточно посмотреть на интерфейс класса, чтобы стало ясно как его использовать. А что у нас в интерфейсе?
C++
1
2
    virtual void run() = 0;                         // Запуск статической системы меню
    virtual void run(ListMenu*) = 0;                // Запуск динамической системы меню
Два метода для какой-то статической системы и какой-то динамической. О чем это вообще?
Ок, второй метод я еще могу понять - передаем список пунктов, которые следует отобразить. А первый? Откуда он возьмет этот список? Интерфейс не дает ответов на эти вопросы.

А теперь главный фейл - метод run чисто виртуальный. Т.е. я, как пользователь, обязан каждый раз для каждого меню писать свой дочерний класс и каждый раз реализовывать логику выбора пункта и отрисовки меню? Вот уж чего мне точно хочется меньше всего. Скорее всего в большинстве случаев логика будет одна: выбрали пункт - вызвали его обработчик - отрисовали меню.
В данном случае эта логика уже реализована в дочернем классе, и тут возникает вопрос - это пример использования или этот класс является частью библиотеки?

Если это пример использования, то он отлично показывает насколько плох базовый класс - 120+ строк кода, да еще и с не пойми зачем появившейся рекурсией. В моей маленькой голове не укладывается зачем методу run() может потребоваться вызывать себя.

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

Дальше смотреть смысла нет, ибо даже если я и решусь реализовывать метод run в своем классе меню, то мне придется смотреть в секцию protected и разбираться какой порядок вызова предполагают предоставляемые методы.

Еще класс навязывает свой способ отрисовки. У меня, например, нет заголовочного файла msoftcon.h (я так понимаю, функции для работы с псевдографикой объявлены в нем).

В общем, напишите для начала простое текстовое меню... Тут еще есть какие-то списки менюшек - не надо. Пусть будет один уровень.
0
Антикодер
Эксперт функциональных языков программирования
1889 / 871 / 48
Регистрация: 15.09.2012
Сообщений: 3,092
23.02.2014, 09:40
Цитата Сообщение от Bretbas Посмотреть сообщение
XRuZzz, я не понял, какой сущности нет в названии моего класса?Если я переименую его в AbstractInterface то будет у него сущность?или я вас не правильно понял?объясните пожалуйста.
а про какие пространства имен идет речь?у меня в классе используется только одно пространство имен std и больше ничего.
ну скажем если поместить Interface в пространство имен gui, становится несколько понятнее. Однако вы используете текстовый режим, поэтому это скорее не gui, а view.
Класс относится к сущности представления главного окна программы. в MVC паттерне я бы назвал его как то вроде MainFormViews.
Я к тому что по названию класса Interface нельзя догадаться относится ли он к главному окну, либо у вас он нужен для какого нить протокола, либо ещё какой-нить интерфейс для работы с реализациями абстрактных классов, который никак не относится к выводу в консоль.
Впрочем еслu вам не нравumcя мой подход, вы можеmе проuгнорuроваmь моё сообщенuе.

Во многом согласен c 0x10.
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
23.02.2014, 22:39  [ТС]
XRuZzz, я не хочу игнорировать никакое сообщение, ибо дальше я буду выкладывать уже сами игрушки с использованием этого класса меню.Я хочу преслушиваться к каждому мнению, чтобы добиться как можно идеальной техники кода.
Итак,снова я вас не понимаю, мне нужно мой класс переименовать в MainFormViews для лучшего представления того,что данный класс делает?)
А с пространством имен снова не понял(
Вы можете,если вам не сложно, изменить мой код и выложить мне?
0
Антикодер
Эксперт функциональных языков программирования
1889 / 871 / 48
Регистрация: 15.09.2012
Сообщений: 3,092
24.02.2014, 09:40
Цитата Сообщение от Bretbas Посмотреть сообщение
Итак,снова я вас не понимаю, мне нужно мой класс переименовать в MainFormViews для лучшего представления того,что данный класс делает?)
в данном случае слово Form я использую когда есть графический интерфейс, Views если применяется паттерн MVC(о нём можно почитать где угодно)
К вашему коду естественно такое название мало подходит. Техника зависит от опыта, опыта вряд ли вам в форуме за пару дней сильно улучшить технику программирования.
Чтоб углубится в мои подходы к программированию. Нужно потратить значительное время на изучение сайта www.uml2.ru.
вот что пишет Страуструп:
The question ‘‘How does one write good programs in C++?’’ is very similar to the question ‘‘How
does one write good English prose?’’ There are two answers: ‘‘Know what you want to say’’ and
‘‘Practice. Imitate good writing.’’ Both appear to be as appropriate for C++ as they are for English
– and as hard to follow.
Но при это с "Imitate" я не очень согласен.
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
25.02.2014, 00:30  [ТС]
XRuZzz,вы можете сказать,кроме как названия класса,что нибудь нужно менять еще?может в самом классе нужно изменить что нибудь?или все как надо там?
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
26.02.2014, 02:47  [ТС]
ммммм?)
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
27.02.2014, 22:06  [ТС]
Надеюсь вы не отписались от моей темы,потому что я продолжаю!)
В этот раз я выкладываю прикладное приложение для создания карт моих будущих игр)Класс интерфейса(меню) использован тот же,что я и выкладывал)
Итак жду снова ваших мнений и предложений!
Вложения
Тип файла: 7z CreatorMaps_v.beta.7z (364.2 Кб, 12 просмотров)
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
01.03.2014, 00:25  [ТС]
неужели все отписались от темы?)
0
Каратель
Эксперт С++
6610 / 4029 / 401
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
01.03.2014, 01:58
Цитата Сообщение от Bretbas Посмотреть сообщение
неужели все отписались от темы?)
Создание игр в текстовом режиме
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
01.03.2014, 02:30  [ТС]
0x10, хм...странно,я ваш комментарий почему-то пропустил.Вот что значит сидеть с мобильного в интернете(

Мой класс Interface является библиотекой,пользователь должен будет создать дочерний класс,чтобы начать использовать и создавать меню.Его нужно создавать только в функции run(),если пользователь хочет создать меню еще до компиляции,тоесть статически,ну или использовать run(ListMenu*),для того,чтобы создать меню уже динамически.Только за этим я разделил эти две функции.
Рекурсия использована,для перехода между списками иерархии меню и не больше.
120 строк...я согласен,но что убрать тогда,чтобы сделать базовый класс меньше?
объясните плизз

Добавлено через 2 минуты
Jupiter,а что вы скажете по поводу "создания карт"?)
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
01.03.2014, 06:43
Цитата Сообщение от Bretbas Посмотреть сообщение
Его нужно создавать только в функции run(),если пользователь хочет создать меню еще до компиляции,тоесть статически,ну или использовать run(ListMenu*),для того,чтобы создать меню уже динамически.Только за этим я разделил эти две функции.
Вопрос: а на каком основании класс, который по идее должен быть не более чем контейнером с минимальной логикой, делает предположения о том, на каком этапе у пользователя есть данные? Второго метода вполне достаточно - в него пользователь может передать как список, сформированный на этапе выполнения, так и зашитый жестко в код.
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
02.03.2014, 01:51  [ТС]
0x10,я вас понял...все переделаю нафиг)завтра выложу)а что скажете про создание карт?)
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
02.03.2014, 08:20
Лучший ответ Сообщение было отмечено Bretbas как решение

Решение

Было бы желание, а разнести можно за каждую строчку... Я не уверен, имеет ли смысл расписывать или пусть автор дойдет своим умом.

Пробежимся раз по интерфейсам и местами по реализации. Дисклеймер: все сказанное - не прямое руководство к действию.

Посмотрим на интерфейс класса Matrix. В паблике у нас два конструктора: с параметрами и без.
Внимание, вопрос: какой смысл автор вкладывает в конструктор матрицы без параметров? Что должно произойти? Создаться матрица размера 0х0? Как потом с ней работать? По факту выясняется, что этот конструктор не делает ничего. видимо, его и быть не должно.

Смысл конструктора с двумя параметрами интуитивно понятен - создание матрицы размера rows*cols. Забегая вперед, реализация конструктора не соответствует ожиданиям.

В публичном доступе также есть данные: собственно, сама матрица и ее размерности. Причем ни о какой инкапсуляции и речи нет - пользователю навязывается тот факт, что матрица реализована как двумерный массив, что, кстати, может быть и иначе. Более того, массив этот всегда фиксированного размера.
Размерности матрицы также ничем не защищены и могут быть изменены независимо. Т.е. где-то в коде я могу поменять, например, высоту, а в другом месте - вылететь за пределы массива при обходе матрицы.

В общем, интерфейс неудобен, не является универсальным и вообще потенциально опасен в использовании.

Еще интересности в приватной части: некая функция Mod_. Комментарий сообщает, что это проверка четности. Тут надо вспомнить, что есть оператор %, которым можно проверить четность. И вообще: какое отношение обычная операция с двумя целыми числами имеет к матрице?

Посмотрим теперь на реализацию.
Реализация конструктора, как я уже заметил выше, дикая. Внезапно конструктор устанавливает цвета в терминале, выводит сообщения в случае ошибок и, что еще круче, в случае ошибки вызывает exit().
Разделите данные и представление. Матрица - это всего лишь контейнер объектов, никакого отношения к представлению он не имеет. Более того, в нем не должны фигурировать никакие ограничения по размеру матрицы относительно размера окна.

В общем, тут две сущности слились в одну: сама матрица и ее представление в окне.

Метод Mod_ делает странное и не соответствующее комментарию. Проверяет он делимость первого аргумента на второй. Как я уже говорил, тут не нужны циклы, а есть оператор %.

Еще у класса есть производный - MatrixChild, который не расширяет функционал базового ничем. Следовательно, и быть его не должно.

Класс Cursor.
Аналогичная проблема с инкапсуляцией - координаты открыты, доступны для изменения.
Главная неожиданность - курсор ссылается на матрицу. Все ради того, чтобы нельзя было сместить его за пределы матрицы. Опять же странная логика. Матрица - контейнер, не важно как она отображается. Курсор - пассивная структура со своей позицией. Мне видится, что явно не ему принимать решение куда двигаться можно, а куда нельзя.

Ну а класс Map - это просто свалка. Тут и редактирование, и доступ к файловой системе, все вперемешку.
Миниатюры
Создание игр в текстовом режиме  
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
03.03.2014, 02:19  [ТС]
0x10, слушайте,по вашим комментарием хочется все взять и удалить нафиг,и не делать ничего больше...но надо,надо учиться)на счет сущностей,что каждому классу делать,а что не делать,это вы про MVC наверное?)Если да,то есть какая нибудь хорошая книга по MVC с примерами на C++?Не подскажете?
0
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
03.03.2014, 05:54
Цитата Сообщение от Bretbas Посмотреть сообщение
слушайте,по вашим комментарием хочется все взять и удалить нафиг
Ну это одна из причин, по которой я сомневался: писать или не писать. Как вариант, можно было просто дать реализовать несколько игрушек по этому шаблону, чтобы, если сильно повезет, Вы сами прошлись по граблям.

Например, из моего поста не ясно почему курсор не может ссылаться на карту. Ведь и так все работает. Да и я сходу не придумаю пример когда все будет плохо. Если только не допустить, что в других местах программы (в менюшках или еще где) возникнут курсоры с теми же данными (координатами), но с другим поведением (или с другими допустимыми границами).

При разработке маленького монолитного приложения, в котором переиспользовать особо нечего (или кажется, что нечего) действительно может показаться, что все это не нужно. Но после написания нескольких таких приложений станет очевидно, что какие-то части кода дублируются во всех практически без изменений. И тогда захочется общие части вынести в библиотеку - и тут уже ее нужно сделать универсальной. Было бы дико, если бы контейнеры стандартной библиотеки в Вашей программе что-то сами писали в stdout, так?

Мне, например, видится, что логику обработки навигации по меню можно обобщить и не заставлять клиента каждый раз собирать по кирпичикам метод run. Это как пример.

Цитата Сообщение от Bretbas Посмотреть сообщение
и не делать ничего больше
Делать надо. Забег по граблям, с кучей шишек и все такое.

Цитата Сообщение от Bretbas Посмотреть сообщение
на счет сущностей,что каждому классу делать,а что не делать,это вы про MVC наверное?
Ну так или иначе всегда все сводится к разделению данных, логики и представления. Прям книга по одному этому паттерну - наверное, слишком жирно. А вот статей погуглить можно. Сходу нашел пару, глянул по диагонали: вроде все по теме:
http://ru.wikiversity.org/wiki... 0%BA%D0%B8
http://rsdn.ru/article/patterns/generic-mvc.xml

Только без фанатизма. Не обязательно всегда слепо следовать паттерну в том виде, в котором он реализован в примере. Подвижки допустимы.

Почитать можно Макконнелла - "Совершенный код". Там в основном капитанство, но некоторые эвристические принципы описаны, лишним не будет. "Паттерны проектирования" GoF - хорошая, но опять же надо без фанатизма.
0
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
06.03.2014, 00:04  [ТС]
0x10, слушайте...я читаю данные вами статьи про MVC,но не могу понять как разделить данные...мне до сих пор кажется,что они разделены( Я на счет "создания карт"
Вы можете мне словами рассказать,что именно нужно разделить,и к примеру каким образом выводить сообщение об ошибки,если я введу слишком большие размеры матрицы...Ведь манипуляции с матрицей это и есть МОДЕЛЬ,так?Передача размеров матрицы происходит в ПРЕДСТАВЛЕНИИ,которое в свою очередь передает эти размеры КОНТРОЛЛЕРУ на проверку,так?И взависимости прааильные ли они или нет,идем дальше к МОДЕЛИ или ПРЕДСТАВЛЕНИЮ для отображения соответствующего сообщения.Значит мне нужно делать 3 класса - МОДЕЛЬ,ПРЕДСТАВЛЕНИЕ,КОНТРОЛЛЕР для осуществления работы с матрицей?И так нужно и для класса Map и остальных классов?так чтоли?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
06.03.2014, 00:04

ООП иерархия классов с выводом в текстовом режиме
Помогите с решением &quot;Дана иерархия классов числа-числа кратные 5-числа кратные 25. Написать программу с выводом объектов указанных классов...

Нарисовать мышью прямоугольник в текстовом режиме экрана
Помогите разобраться.. Нужно нарисовать прямоугольник (любыми символами) в текстовом режиме экрана с помощью мышки. Ну я пытался...

Как сделать прокрутку (в текстовом режиме) и менюшку в turbo c
(Turbo c)Если прогамма выводит на экран большое кол-во информации, то некоторая её часть становится недоступной, как же сделать прокрутку...

Работа с экраном в текстовом режиме (вывод всех цветов фона, разделяя цвета паузой)
Пожалуйста подскажите, как сделать вывод всех цветов фона, разделяя цвета паузой. Задание: Дополнить меню функциональной клавишей F6:...

Создание приложения в визуальном режиме
Нужно в визуальном режиме С++ Создать приложение, позволяющее: 1) просматривать в указанном каталоге графические файлы в выбранном...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
FPS контроллер с анимированными Y-Bot и 3D-звуком miniaudio (Box3D, Recast, BehaviorTree.CPP, ozz-animation, ImGui, OpenGL и SDL3)
8Observer8 18.10.2026
Содержание блога | English Version Полное мультиплатформенное руководство по стартовому проекту с FPS-контроллером игрока, анимированными роботами Y-Bot с 4-слойным блендингом, 3D-физикой Box3D,. . .
Локальный http сервер
Argus19 17.10.2026
Локальный http сервер На работе, на двух локальных компьютерах круглосуточно работают программы опроса приборов с записью в книги Excel,которые раз в сутки записываются на сервер компании. Т. к. . . .
Копировать Windows на новый диск на UEFI
damix 17.10.2026
https:/ / uriesk. wordpress. com/ 2016/ 11/ 01/ move-window-10-to-ssd-on-a-uefi-dualboot-system-with-basic-linux-tools/ TL DR Вставляем диск, а старый подключаем через переходник, грузимся с лайва. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru