Форум программистов, компьютерный форум, киберфорум С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
0 / 0 / 0
Регистрация: 16.12.2012
Сообщений: 8
1

Изменение вектора родителя через наследников

22.10.2015, 21:23. Показов 2618. Ответов 5
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
В общем, думала, куда написать... Решила все же сюда.
В данный момент нужно, чтобы программа расставляла, скажем так, шахматные фигуры на поле.
Есть родитель-поле, абстрактный класс фигура, и два наследника, от нее и от поля - еще два класса-фигуры.
Хочу через наследников поменять значения вектора в родителе, но там ничего не фиксируется. Если вызывать метод печати через одного из наследников, то в вектор запишется только то, что задал ему именно этот наследник - второй будет проигнорирован, ну, что логично.
Как можно сделать так, чтобы наследники меняли вектор, как этого хочу я? Чтобы все фигуры были на поле?
Буду благодарна за любые ответы.

chess.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
46
#ifndef CHESS
#define CHESS
 
#include <iostream>
#include <vector>
 
class FieldGeneration
{
protected:
    std::vector <std::vector<int> > field;
public:
    FieldGeneration(); // создание поля
    void PrintField(); // вывод текущего вида поля
    ~FieldGeneration(); // удаляем поле
};
 
class Figure
{
public:
    virtual void ShowFigMoves(int, int) = 0; // показывает, куда можно походить
    virtual void FigMoving(int, int) = 0; // определяет движение фигуры
};
 
class Bishop : public Figure, public FieldGeneration
{
    const int bbs1 = 1, bbs2 = 2, wbs1 = 3, wbs2 = 4;
    int bbsx1, bbsy1, bbsx2, bbsy2, wbsx1, wbsy1, wbsx2, wbsy2;
public:
    Bishop();
    virtual void ShowFigMoves(int, int);
    virtual void FigMoving(int, int);
    ~Bishop();
};
 
class Rook : public Figure, public FieldGeneration
{
    const int br1 = 5, br2 = 6, wr1 = 7, wr2 = 8;
    int brx1, bry1, brx2, bry2, wrx1, wry1, wrx2, wry2;
public:
    Rook();
    virtual void ShowFigMoves(int, int);
    virtual void FigMoving(int, int);
    ~Rook();
};
 
#endif
chess.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
#include "chess.h"
 
FieldGeneration::FieldGeneration()
{
    field.resize(8);
    for (int i = 0; i < 8; ++i)
        field[i].resize(8);
}
 
void FieldGeneration::PrintField()
{
    for (int i = 0; i < field.size(); ++i, std::cout << std::endl)
        for (int j = 0; j < field.size(); ++j)
            std::cout << field[i][j] << '\t';
    std::cout << std::endl;
}
 
FieldGeneration::~FieldGeneration()
{
    field.clear();
}
 
Bishop::Bishop()
{
    bbsx1 = 0; bbsy1 = 2; bbsx2 = 0; bbsy2 = 5; 
    wbsx1 = 7; wbsy1 = 2; wbsx2 = 7; wbsy2 = 5;
    field[bbsx1][bbsy1] = bbs1;
    field[bbsx2][bbsy2] = bbs2;
    field[wbsx1][wbsy1] = wbs1;
    field[wbsx2][wbsy2] = wbs2;
}
 
void Bishop::ShowFigMoves(int, int)
{
}
 
void Bishop::FigMoving(int, int)
{
}
 
Bishop::~Bishop()
{
 
}
 
Rook::Rook()
{
    brx1 = 0; bry1 = 0; brx2 = 0; bry2 = 7;
    wrx1 = 7; wry1 = 0; wrx2 = 7; wry2 = 7;
    field[brx1][bry1] = br1;
    field[brx2][bry2] = br2;
    field[wrx1][wry1] = wr1;
    field[wrx2][wry2] = wr2;
}
 
void Rook::ShowFigMoves(int, int)
{
}
 
void Rook::FigMoving(int, int)
{
}
 
Rook::~Rook()
{}
main.cpp
C++ Скопировано
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "chess.h"
 
int main()
{
    FieldGeneration f;
    Bishop b;
    Rook r;
    
    b.PrintField();
 
    system("PAUSE");
    return 0;
}
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.10.2015, 21:23
Ответы с готовыми решениями:

Вывод поста, который содержит id категории, её родителя, родителя родителя
Есть 2 таблицы, первая - категории ( category_id, parent_id и т.д), вторая - посты (post_id, category_id) В общем, в...

Вывод полей наследников через foreach из List
Или не обязательно через foreach. Доброго дня! У меня все плохо с основами, потому кидайте, пожалуйста, свои помидоры. Вопрос в...

Изменение родителя в Qt Designer
Не как не могу разобраться как изменить родителя в Qt Designer, например у меня есть форма класса QMainWindow я кидаю на нее виджет...

5
202 / 138 / 88
Регистрация: 21.12.2014
Сообщений: 369
22.10.2015, 22:40 2
Судя по твоему коду, каждая фигура содержит в себе поле. А поле содержит левый вектор векторов. Поле должно быть одно и должно содержать фигуры. Наследование фигуры от поля тут совершенно не нужно. Абстрактный класс тут для вида только, надо поместить в него общие для всех фигур свойства - координаты например. И вектор фигур поместить в поле.
1
542 / 163 / 79
Регистрация: 23.09.2013
Сообщений: 316
22.10.2015, 23:16 3
Shinichi, Здравствуйте, судя по всему Вы не правильно используете в своей программе наследование. 3 момента:
1) Наследование реализует взаимосвязь между сущностями типа "является" - Иерархия типа House -> Building -> Object - можно читать как - Любой дом является строением, любое строение является объектом (у наследования есть свойство транзитивности) любой дом является объектом.

Если так прочесть Ваш код, то получится, что Bishop является фигурой (что вполне корректно), но при этом Бишоп является полем (FieldGeneration). Т.е. фигура, содержит в себе все свойства целой доски - это не верно.
2) Наследование реализации (наследование от не полностью абстрактного класса) позволяет получить и использовать весь код, который был написан в базовом в классе, в классе наследнике. "Отказ от наследства" (Refused Bequest) - т.е. намеренное не использование кода базового класса в наследнике - является известным "запахом кода" - которого следует избегать. (Подробнее читайте в Фаулер М., Бек К., Брант Д., Робертс Д., Апдайк У. Рефакторинг: улучшение существующего кода)

В Вашем коде - каждая фигура получила бы код FieldGeneration - но явно они не стали бы его использовать целиком.

3) Множественное наследование - позволяет наследовать класс сразу от нескольких классов. Это мощный инструмент, позволяющий, например, один объект интерпретировать двумя различными образами (Вася Пупкин - с одной стороны - студент, с другой стороны - музыкант). Множественное наследование реализаций - с одной стороны, позволяет получить не только интерфейс, но и поведение наследованных классов. Но множественное наследование сопряжено со специфическими проблемами (Подробнее читайте "deadly diamond of death").
В общем случае - не обоснованное множественное наследование реализаций как минимум - ухудшит структуру программы (повышенная связанность, побочные эффекты модификаций), и быстродействие (особенно в случае виртуального наследования).

В Вашем случае множественное наследование не оправдано.

Общие советы - использовать композицию вместо наследования. Композиция предполагает отношение часть - целое. Т.е. доска состоит из ячеек. В каждой ячейке могут быть фигуры. В зависимости от типа фигуры может быть получено разное значение ходов для фигуры. В общем случае фигуры не должны будут расставлять другие фигуры по полю, более того - в идеале один тип фигур не должен знать о другом типе фигур. Типы фигур не должны быть заданы жестко - а образовывать иерархию - Конкретная Фигура -> Фигура (Шашка -> Фигура). И полиморфно реализовывать методы взаимодействия с фигурой.
1
0 / 0 / 0
Регистрация: 16.12.2012
Сообщений: 8
22.10.2015, 23:40  [ТС] 4
Единственное, что значит "вектор фигур поместить в поле"?

Добавлено через 10 минут
Спасибо за развернутый ответ. Ошибку поняла, но пока в тумане мысли о том, как грамотно все же организовать решение задачи.
Вариант два - поле получало бы координаты фигур через сеттеры\геттеры и обновляло его, а две фигуры, в моем случае - ладья и слон - хранили бы свои координаты. Сейчас буду пробовать это все делать. Чую, и здесь глупость сказанула.
0
542 / 163 / 79
Регистрация: 23.09.2013
Сообщений: 316
23.10.2015, 00:49 5
Лучший ответ Сообщение было отмечено Shinichi как решение

Решение

Shinichi,

Не по теме:

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



Добавлено через 36 минут
Итак, код:
Кликните здесь для просмотра всего текста
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#ifndef CHESS
#define CHESS
 
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
 
struct Pos {
  size_t x;
  size_t y;
};
 
class Figure {
 public:
  virtual std::string TextRepresentation() const = 0;
  virtual bool CanMove(const Pos &from, const Pos &to) = 0;
  virtual ~Figure() {}
};
 
class Cell {
 public:
  Figure *set_figure_inside_cell(Figure *figure) {
    auto old_figure = figure_inside_cell_;
    figure_inside_cell_ = figure;
    return old_figure;
  }
 
  Figure *remove_figure() {
    auto figure_inside_cell = figure_inside_cell_;
    figure_inside_cell_ = nullptr;
    return figure_inside_cell;
  }
 
  Figure *figure_inside_cell() const { return figure_inside_cell_; }
 
  std::string TextRepresentation() const {
    auto figure = figure_inside_cell();
    if (figure != nullptr) {
      return figure->TextRepresentation();
    }
    return ".";
  }
 
 private:
  Figure *figure_inside_cell_ = nullptr;
};
 
class Field {
 public:
  Field(size_t size = 8);
 
  std::string TextRepresentation() const {
    std::string text_representation;
    for (auto line : field_) {
      for (auto cell : line) {
        text_representation +=
            cell.TextRepresentation() + kCellSeparationSymbol;
      }
      text_representation += kLineSeparationSymbol;
    }
    return text_representation;
  }
 
  bool SetFigure(Figure *figure, const Pos &position) {
    auto is_position_valid = IsPositionValid(position);
 
    if (is_position_valid) {
      field_[position.y][position.x].set_figure_inside_cell(figure);
    }
    return is_position_valid;
  }
 
  void SetFigureBack(Figure *figure_from_cell, const Pos &from) {
    assert(field_[from.y][from.x].set_figure_inside_cell(figure_from_cell) ==
           nullptr);
  }
 
  bool MoveFigure(const Pos &from, const Pos &to) {
    auto are_positions_valid = IsPositionValid(from) && IsPositionValid(to);
    if (are_positions_valid) {
      auto figure_from_cell = field_[from.y][from.x].remove_figure();
      if (figure_from_cell && figure_from_cell->CanMove(from, to)) {
        auto figure_inside_destination_cell =
            field_[to.y][to.x].set_figure_inside_cell(figure_from_cell);
        if (figure_inside_destination_cell == nullptr) {
          return true;
        } else {
          SetFigureBack(figure_from_cell, from);
        }
      }
    }
    return false;
  }
 
 private:
  bool IsPositionValid(const Pos &pos) const {
    return pos.y < field_.size() && pos.x < field_[pos.y].size();
  }
 
  const char kCellSeparationSymbol = '\t';
  const char kLineSeparationSymbol = '\n';
 
  std::vector<std::vector<Cell> > field_;
};
 
Field::Field(size_t size) {
  field_.resize(size);
  for (size_t i = 0; i < size; ++i) {
    field_[i].resize(size);
  }
}
 
class Bishop : public Figure {
 public:
  std::string TextRepresentation() const override;
  bool CanMove(const Pos &from, const Pos &to) override;
};
 
class Rook : public Figure {
 public:
  std::string TextRepresentation() const override;
  bool CanMove(const Pos &from, const Pos &to) override;
};
 
#endif
 
/// -----------------------------
 
std::string Bishop::TextRepresentation() const { return "*"; }
 
bool Bishop::CanMove(const Pos &from, const Pos &to) {
  return true;
}  // todo fill with logic
 
std::string Rook::TextRepresentation() const { return "#"; }
 
bool Rook::CanMove(const Pos &from, const Pos &to) {
  return true;
}  // todo fill with logic
 
void ShowField(const Field &field) {
  std::cout << '\n' << field.TextRepresentation() << std::endl;
}
 
int main() {
  Field field;
  ShowField(field);
 
  Bishop b;
  Pos b_pos = {2, 2};
  std::cout << "set bishop figure success:" << field.SetFigure(&b, b_pos)
            << '\n';
 
  Rook r;
  Pos r_pos = {5, 2};
  std::cout << "set rook figure success:" << field.SetFigure(&r, r_pos) << '\n';
 
  ShowField(field);
 
  Pos new_b_pos = {3, 2};
  std::cout << "change bishop position success:"
            << field.MoveFigure(b_pos, new_b_pos);
 
  ShowField(field);
}


Пруф работоспособности:
http://ideone.com/FPPSar

Прошу строго не судить. Я полностью убрал на данный момент ограничения на перестановку фигур (оставил заглушки с todo). Кроме того, в зависимости от накладываемых требований на функционал - возможно потребуется доработка иерархий и отношений сущностей. Например чтобы суметь взяться за Фигуру - и поставить её в позицию - нужно научить фигуру определять в какой позиции она сейчас находится ( а для этого, возможно, её придется подружить с Cell, а Cell научить понимать свою позицию). Вариантов тут масса, это просто пример рабочий как иллюстрация возможностей реализации через композицию.

Добавлено через 3 минуты
При реализации использован стандарт языка с++11.

Добавлено через 9 минут
Основные идеи - хоть на доске и располагаются все фигуры - она не отвечает за их время жизни (хотя можно использовать и обратный подход). Мы можем установить фигуру на позицию в доске, можем убрать фигуру с позиции доски. Можем передвинуть фигуру (композиция снятия и установки). Доска не знает какая конкретная фигура установлена в ячейке доски. Фигура, ячейка, доска - имеют методы текстового представления своей сущности (для фигуры - просто символ, для ячейки - символ ячейки - если ячейка пуста и символ фигуры если в ячейку установлена фигура, для доски - символы всех ячеек из которых она состоит в отформатированном виде). Символ для фигуры получается из виртуального метода - что позволяет полиморфно менять его от фигуры к фигуре. (Хотя можно было сделать базовый класс, в который мы устанавливаем этот символ как строку - и он её отображает - вот оно многообразие реализаций). Далее текстовое представление может быть отображено (например в поток вывода). В нашем случае информацию для отображения содержит std::string - в общем случае это был бы отдельный абстрактный тип данных. (набор координат, картинка, или целая 3д модель).

Добавлено через 12 минут
Из мыслей пришедших на ум в последний момент:
В моей реализации доска является гарантом соблюдения игровых правил. (Если не считать доступность метода SetFigure) - по крайней мере moveFigure - защищает от нечестных с точки зрения игровых правил действий. Но в целом имело бы смысл разнести данную доску на 2 разные сущности - доска и игра (Game) - в игре были бы методы связанные с игровой логикой - а доска осталось бы для презентации игровой доски и не более - позволяющей делать с собой что угодно (В реальности же доска тебя не накажет за то что ты пешкой начал ходить как ферзём). Это в частности позволило бы с одной и той же доской и фигурами играть в разные игры (Шахматы и шашки например).
Еще одна мысль - игре понадобится отслеживать состояние доски потому-что, например, да фигура может походить по диагонали... но что она не может перепрыгнуть через другие фигуры, стоящие на её пути - скажет только игра, обладающая знаниями о том, что находится на пути следования фигуры.

Добавлено через 3 минуты
Еще один момент - фигурам нужно будет присвоить принадлежность к сторонам (белые, черные) - и дописать логику замены фигур на доске. (Например, если белая пешка наехала на поле с белым же ферзем - пользователю должно написать, что так ходить нельзя) А вот если белая пешка попала на поле с черным ферзем - она его съедает - поле занимается пешкой, ферзь удаляется, пользователю записывают счет. Кроме того нужно было бы добавить контроль последовательности ходов и сущность игрока. Т.е. на верхнем уровне были бы написаны строки, позволяющие ходить по очереди игроку белых и игроку черных, при этом, если игрок белых пытается взять фигуру черных - он получает сообщение об ошибке, что мол не твоё - не трожЪ).
1
0 / 0 / 0
Регистрация: 16.12.2012
Сообщений: 8
23.10.2015, 01:20  [ТС] 6
Cпасибо огромное. Буду разбираться, дописывать.
Не передам Вам, как Вы помогли.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.10.2015, 01:20
Помогаю со студенческими работами здесь

ООП - изменение переменной родителя
Простой скрипт В корне есть переменная $SERVER_PARAMS{location} = 1; В пакет Components передаю весь хэш %SERVER_PARAMS ...

Изменение вектора. Наибольший элемент вектора
Добрый день, нужна оценка кода. Пропустил занятия, делал по теории, опирался на массивы. Скажите, правильно ли реализовано? Создать...

CSS и изменение стиля родителя при нажатии на дочь
Как это сделать? Имеется: &lt;div class=&quot;bag&quot;&gt;&lt;div class=&quot;tes&quot;&gt;&lt;/div&gt;&lt;input class=&quot;bt&quot; type=&quot;submit&quot;...

Пропорциональное изменение размеров div (от родителя до всех вложенных)
Есть такой код: &lt;div id=&quot;dsk-l&quot;&gt; &lt;div id=&quot;dsk-l-brd&quot;&gt;&lt;/div&gt; &lt;div id=&quot;dsk-l-stp&quot;&gt;&lt;/div&gt; &lt;div id=&quot;dsk-l-trmz&quot;&gt;&lt;/div&gt; &lt;div...

Как при клике взять ID родителя и скрыть дивы с классом взятого ранее родителя?
Здравствуйте друзья, столкнулся с задачкой для решения которой у меня не хватает опыта JS программировании. Имеется сайт с системой...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему

Редактор формул (кликните на картинку в правом углу, чтобы закрыть)
Новые блоги и статьи
Лучшие практики оптимизации Docker Image
Mr. Docker 13.03.2025
Размер Docker-образа влияет на множество аспектов работы с контейнерами. Чем больше образ, тем дольше его загрузка в реестр и выгрузка из него. Для команд разработки, работающих с CI/ CD пайплайнами,. . .
Вопросы на собеседовании по Docker
Mr. Docker 13.03.2025
Ты сидишь напротив технического специалиста, и вдруг звучит вопрос про Docker Swarm или многоэтапные сборки. Пот на лбу? Не переживай, после этой статьи ты будешь готов ко всему! Эта статья будет. . .
Поиск текста в сносках : замена дефиса на тире или тире на дефис...
РоΜа 13.03.2025
Нужно было найти текст в сносках и заменить. Почему-то метод селекшн не сработал. . . пришлось гуглить. найденный на форумвба код пришлось править. Смысл - заменяет в сносках дефисы и тире на нужные. . . .
Real PATH definitions in bash scripts
jigi33 13.03.2025
Как поймать путь и путь к директории относительно запускаемого файла в BASH 1. поймать путь через вывод $(pwd) 2. более правильно - на основе realpath (см. скриншот)
Django или Flask: что выбрать для веб-разработки на Python
py-thonny 13.03.2025
Django – это высокоуровневый фреймворк, который придерживается философии "всё включено". Он предоставляет разработчику готовые решения для большинства типичных задач веб-разработки: от аутентификации. . .
Непрерывное развертывание в Java с Kubernetes
Javaican 13.03.2025
Чем так привлекателен Kubernetes для развертывания Java-приложений? Этот оркестратор контейнеров позволяет автоматизировать развертывание, масштабирование и управление контейнеризированными. . .
Предотвращение XSS, CSRF и SQL-инъекций в JavaScript
run.dev 13.03.2025
JavaScript занимает первые позиции среди языков веб-разработки, но его распространенность делает его привлекательной целью для злоумышленников. Межсайтовый скриптинг (XSS), межсайтовая подделка. . .
PHP 8: JIT-компиляция и улучшение производительно­сти
Jason-Webb 13.03.2025
PHP никогда не славился своей скоростью. Многие сталкивались с проблемами производительности при работе со сложными вычислениями или обработкой больших объемов данных. Традиционная модель выполнения. . .
Сериализация данных с Apache Avro в Kafka
Javaican 12.03.2025
Apache Kafka стала одним из ключевых решений для работы с большими потоками данных. Однако с ростом объемов передаваемых данных возникает проблема: как эффективно сериализовать и десериализовать. . .
Создание потребителей Kafka с помощью Reactor Kafka
Javaican 12.03.2025
Reactor Kafka — это библиотека, объединяющая Apache Kafka с реактивным программированием на базе Project Reactor. Такое сочетание позволяет строить неблокирующие, асинхронные приложения с контролем. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru
Выделить код Копировать код Сохранить код Нормальный размер Увеличенный размер