2014-09-24 4 views
6

Я новичок в C++ и переношу по Java-проекту на C++.Массив объектов, разница между Java и C++

Рассмотрим следующий Java-код, где Кусок класс, представляющий шахматной фигуры:

Piece[][] myPieces = new Piece[8][8]; 

Он создает массив, в котором все элементы равны нулю.

Как я могу достичь того же в C++? Я пробовал:

Piece* myPieces = new Piece[8][8]; 

Но это создаст массив со всеми элементами, инициализированными конструктором по умолчанию.

Благодаря

Edit: Я хочу C++ код, чтобы быть эффективным/элегантный и я не забочусь ни wnant скопировать пасту с Java на C++. Я рад сильно изменить структуру кода, если это необходимо.

Edit 2: Кода для шахматной программы, размер массива будет никогда изменения и производительность критичны.

+2

Не разумное мышление, если сравнивать два разных языка. –

+2

Согласовано. Не пытайтесь нажимать Java 1: 1 на другой язык. – deviantfan

+4

Если сравнение с Java вас беспокоит, просто подумайте об этом как «Как я могу получить 2D-массив дополнительных объектов на C++?» Я думаю, что ответ в достаточной степени убедит спрошенного, что C++ и Java следует рассматривать по-разному. –

ответ

3

Ответ зависит, потому что вопреки Java, на C++ у вас есть разная семантика собственности и управление жизненным циклом объекта (эти два идут рука об руку).

Если вы хотите моделировать объекты, похожие на Java, можно было бы написать:

using PiecePtr = std::shared_ptr<Piece>; 
std::array<std::array<PiecePtr, 8>, 8> Pieces; 

shared_ptr имеет ту же семантику на объект Java (передать его вокруг, где и это время жизни гарантировано, пока есть ссылки к нему).

Если вы хотите моделировать наблюдаемые объекты (т.е. массив не владеет им), вы должны написать:

using PiecePtr = Piece*; 
std::array<std::array<PiecePtr, 8>, 8> Pieces; 

Это гарантирует, что, когда Pieces объект разрушается, фактические части сами по себе остаются в памяти ,

Если вы хотите моделировать уникальные объекты, принадлежащие Pieces массива, вы должны использовать:

using PiecePtr = std::unique_ptr<Piece>; 
std::array<std::array<PiecePtr, 8>, 8> Pieces; 

Это гарантирует, что, когда объект Кусочки разрушается, фактические куски сами разрушаются, а также.

+0

Неудача на исполнителе и на хорошем C++ для этой ситуации: Полиморфизм является серьезным излишеством и не хорош для производительности. – Deduplicator

+0

@ Дедупликатор, какой полиморфизм? std :: array не является полиморфным, также не являются std :: unique_ptr или std :: shared_ptr (я не уверен, о чем вы говорите). – utnapistim

+0

Вы используете указатели на 'Piece's, и нет причин использовать их, если' Piece' не является полиморфным или необязательным. И учитывая ограничения OPs на решение, полиморфизм отсутствует, а несуществующая 'Piece' должна быть смоделирована с помощью заполнителя-' Piece'. – Deduplicator

2

В C++ вы могли бы сделать что-то вроде:

std::vector<std::vector<std::unique_ptr<Pieces>>> myPieces; 
+1

Неудача на «хорошем C++» для этой ситуации, также на «performant». – Deduplicator

+0

Это не «то же самое в C++». Это массив указателей _variable length_ и _owned_. Java не имеет указателей на всех (только общий). – utnapistim

2

семантически эквивалентно бы:

Piece* myPieces[8][8] 

в Java только знает объекты в куче, указатели.

As Piece, вероятно, не является окончательным классом, но имеет короля, королеву, это путь.

+0

-1: Нет, он не будет компилироваться в C++ (массивы не могут иметь размер не указан). Во всяком случае, это плохой подход на C++. – milleniumbug

+0

@milleniumbug: добавлено 8s; Я больше интересовался типом, указателем, так как я думаю, что использование указателя имеет значение здесь. Как насчет наследования? Или вы имеете в виду плохой подход с использованием матрицы? Благодарю. –

+0

Удалено -1, так как исправлена ​​моя основная жалоба. Однако ИМХО это использование наследования кажется вынужденным, так как есть только несколько видов шахматных фигур. (для хранения разных типов требуется использование указателя/умного указателя и довольно навязчивый) – milleniumbug

1

В C++ созданный объект (даже в массиве) создается с помощью конструктора по умолчанию.Это одно из важных отличий от java. Если вы хотите вызвать конструкторы по отдельности, просто используйте вектор векторов и добавьте каждый из них.

7

Самого простой способ объявить 8x8 массив дополнительных объектов в C++, как так:

boost::optional<Piece> myPieces[8][8]; 

Тип boost::optional представляет собой дополнительный объект (например, ваша обнуляемой ссылку в Java), который не имеет все ловушки использования типов указателей. Он должен быть доступен как часть стандартной библиотеки в ближайшие несколько лет.

Вы можете предпочесть использовать тип std::array, который является инкапсуляция массивов фиксированного размера, что позволяет им рассматривать как граждане первого класса, а также обеспечивает более приятный интерфейс:

std::array<std::array<boost::optional<Piece>, 8>, 8> myPieces; 

Если вы хотите чтобы иметь возможность изменять размеры ваших массивов во время выполнения, вместо этого рассмотрите std::vector.

+0

Java 8, наконец, имеет 'Необязательный <>' тоже. Приятно о 'array' тоже. –

+0

Может ли boost :: optional негативно повлиять на производительность? – Romain

+0

@Romain: Да, потому что 'boost :: optional ' естественно больше, чем 'Piece'. – Deduplicator

0

В C++, вы должны объявить как:

Piece *** myPieces; 

затем выделить как:

myPieces = new Piece **[8]; 

затем,

for (int i = 0; i < 8; i++) { 
    myPieces[i] = new Piece *; 
} 

Теперь, если вы делаете,

myPieces[0][0] = new Piece(); // C++, calls default constructor of Piece 

В Java

Piece[][] myPieces; 
myPieces = new Piece[8][8]; 

теперь, если вы делаете,

myPieces[0][0] = new Piece(); // Java, calls default constructor of Piece 

Поскольку вы 8x8 уже известно, вы также можете объявить как (в C++):

Piece * myPieces[8][8]; // 64 pointers preallocated as 8 rows, 8 cols 

затем ,

Теперь, если вы это сделаете,

for (int i = 0; i < 8; i++) { 
    for (int j = 0; j < 8; j++) { 
    myPieces[i][j] = new Piece(); // or new Pawn or new Knight etc, subclass of Piece 
}} 

или выделить по необходимости, например.

myPieces[0][0] = new Piece(); // or new Pawn or new Knight etc, subclass of Piece 
+1

Почему бы не поменять векторы? Также важна скорость, а косвенные массивы 2d имеют низкую производительность кеша. –

+0

Я только что ответил на вопрос, не улучшился, использование вектора обеспечит определенную абстракцию, но это не поможет понять разницу в ссылке на Java и указателе на C++. Итак ... –

+0

Это путь, большинство других ответов просто ужасно многословны и неэффективны. Кроме того, как заявила OP, плата имеет фиксированный размер, поэтому вы можете рассмотреть что-то вроде «Piece * myPieces [8] [8]». – XDnl

5

Как вы хотите его производительным, и право на C++ вместо тупого перевода, как об этом:

Использовать размер-1 POD-типа для части.
Добавить все удобства-методы, которые вы могли бы хотеть к нему:

struct Piece { 
    unsigned char value; 
    constexpr Piece() : value() {} 
    constexpr operator bool() const {return !value;} 
    constexpr bool empty() const {return *this;}; 
    constexpr bool black() const {return value&0x80;} 
    constexpr bool white() const {return value && !black();} 
    constexpr unsigned piece() const {return value & 0x7f;} 
}; 

Теперь это было бы эквивалентно сырой массив:

Piece board[8][8]; 

Или используйте std::array:

#include <array> 
std::array<std::array<Piece, 8>, 8> board; 
+0

Вам не хватает const на ваших методах, и я не понимаю, как работает пустая функция. –

+0

@NeilKirk: Добавлено, также 'constexpr', пока я был на нем. – Deduplicator

+0

А вот это: Конвертировать '* this' в' bool', что означает использование 'operator bool'. – Deduplicator

1

У меня есть нет опыта работы с java, но я верю из того, что у меня получилось, что это может быть хорошей заменой в C++:

std::array<std::array<unique_ptr<foo>, 8>, 8> arr = {}; 

if(arr[2][3].get() == nullptr) // Can check for null elements 
    std::cout << "this is null"; 

arr[3][4].reset(new foo()); // Initialize an element 
  • смарт-указатель позволяет избежать утечек памяти
  • std::array обеспечивает представления, сравнимые с нормальным массив C
  • aggregate initialization обеспечивает каждый указатель нулевое значение
  • фиксированный размер, как Java массив
+0

Не будет 'arr = {};' также работать? –

+0

Да, и это, наверное, менее уродливо, чтобы видеть. Иногда я определенно надуман, извините: P –

1

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

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

std::array<std::array<Peice *, 8>, 8> Board; 
std::array<Piece, 32> Pieces; 

Вы можете представить пустую ячейку как нулевой указатель.

Если вы хотите, все в том же массиве, вы можете просто использовать

std::array<std::array<Peice, 8>, 8> Board; 

Но вам нужно будет создать «фиктивный» значение кусок, чтобы представлять собой пустую ячейку.

Примечание: динамическое распределение памяти отсутствует, а данные компактны в памяти, поэтому улучшена производительность кеша.

Piece может быть перечислением или структурой с некоторыми полезными функциями геттера, такими как IsWhite.

Смежные вопросы