как добраться до поля динамического массива 2D-объектов?

#c #arrays

#c #массивы

Вопрос:

Я хотел бы создать игру Конвея о жизни. У меня есть два класса Cell и Board, и в Board я хочу создать ячейку типа 2D динамического массива. Я не имею ни малейшего представления, как добраться из этого массива до полей ячейки. Компилятор показывает

C:UsersJaDesktopObjectProjectObjectGameOfLifeboard.cpp:54 : ошибка: C2248: ‘Cell::state_current’: не удается получить доступ к закрытому члену, объявленному в классе ‘Cell’

Извините за мой английский.

 #ifndef CELL_H
#define CELL_H

#include <iostream>
#include <cstdlib>

using namespace std;

class Cell
{
  bool state_current;
  bool state_future;
  int neighbors;

  void editCell(bool n_state);

public:
  Cell();
  void show();
  void edit();
};
  

cell.cpp

 #endif // CELL_H
#include "cell.h"

Cell::Cell()
{
  int a=0;

  a=rand()%2;
  if(a==1)
    state_current=true;
  else
    state_current=false;

  state_future=false;
  neighbors=0;
}

void Cell::show()
{
  if(state_current==true)
    cout<<'X';
  else
    cout<<'O';
}

void Cell::editCell(bool n_state)
{
  state_current=n_state;
}

void Cell::edit()
{
  int option;

  cout<<"choose avaible option:n0.deadn1.alive"<<endl;

  cin>>option;
  while(option!=1 amp;amp; option!=0)
  {
     cout<<"choose avaible option"<<endl;
     cin>>option;
 }

  if(option==1)
    editCell(true);
  else
    editCell(false);
 }
  

board.h

 #ifndef BOARD_H
#define BOARD_H

#include "cell.h"

class Board
{
    int v;
    int c;
    Cell **t;
public:
    Board(int a=10, int b=10); //konstruktor z wartościami domyślnymi
    void showBoard();
    void getSize();
    void createBoard();
    void checkNeighborhood(int x, int y);
    void rules(int x, int y);
    void nextGen();
};

#endif // BOARD_H
  

board.cpp

 #include "board.h"

Board::Board(int a,int b)
{   
    v=a;
    c=b;
    t=new Cell *[v];

    for(int i=0; i<v; i  )
        t[i]=new Cell [c];
}

void Board::createBoard()
{
    t=new Cell *[v];

    for(int i=0; i<v; i  )
        t[i]=new Cell [c];
}

void Board::showBoard()
{
    for(int i=0; i<v; i  )
    {
        for(int j=0; j<c; j  )
            t[i][j].show();
        cout<<endl;
    }
}

void Board::getSize()
{
    int a,b;

    cout<<"Enter natural numbers"<<endl;
    cin>>a;
    cin>>b;
    while(a<1 amp;amp; b<1)
    {
        cout<<"Board can't have this size. Enter natural numbers"<<endl;
        cin>>a;
        cin>>b;
    }
    v=a;
    c=b;
}

void Board::checkNeighborhood(int x, int y)
{
    for(int i=x-1; i<x 2; i  )
        for(int j=y-1; j<y 2; j  )
            if(i>=0 amp;amp; i<v amp;amp; j>=0 amp;amp; j<c)
                if(!(i==x amp;amp; j==y))
                    if(t[i][j].state_current==true)//first crash
                        t[i][j].neighbors  ;
}

void Board::rules(int x, int y)
{

    if(t[x][y].state_current==true)
        if(t[x][y].neighbors<2 || t[x][y].neighbors)
            t[x][y].state_future=false;
        else
            t[x][y].state_future=true;
    else
        if(t[x][y].neighbors==3)
            t[x][y].state_future=true;
        else
            t[x][y].state_future=false;
}

void Board::nextGen()
{
    for(int i=0; i<v; i  )
        for(int j=0; j<c; j  )
        {
            rules(i,j);
            t[i][j].state_current=t[i][j].state_future;
        }
}
  

Ответ №1:

Проблема именно в том, что в нем написано, что это так; вы пытаетесь изменить частный атрибут другого объекта. В этой строке:

      if(t[i][j].state_current==true)//first crash
  

Обратите внимание, что вы обращаетесь прямо к объекту и пытаетесь ухватиться за атрибут (переменную-член), а не спрашиваете ячейку о ее состоянии.

Часть цели инкапсуляции функциональных возможностей и придания им приватности состоит в том, чтобы предотвратить проникновение других объектов внутрь и их изменение волей-неволей. Даже если вы просто выполняете проверку здесь, правильный способ сделать это — использовать объектный метод для опроса объекта. Добавьте что-то подобное в свой Cell.h и Cell.cpp как общедоступная функция:

 boolean Cell::status()
{
  return state_current;
}
  

Затем назовите это следующим образом:

 if(t[i][j].status()==true)
  

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

Комментарии:

1. Итак, самый простой способ решить эту проблему — создать и использовать методы set и get ячейки?

2. ДА. В краткосрочной перспективе это требует больше кода, чем традиционный подход C (императивный стиль), когда вы достигаете и делаете то, что хотите, но в долгосрочной перспективе, по мере роста проекта в размерах, это абсолютно правильный и самый простой подход.

3. Создайте функции-члены для всех поведений, которые есть у ячейки, и для всех вещей, о которых вы хотите спросить ячейку. Затем используйте их. Сделайте ячейку непрозрачной. Хотя вы можете больше не использовать этот код, в более крупном проекте это приводит к созданию кода, который можно легко извлечь и перенести в другие проекты, если вы правильно определили интерфейс к объекту.