Как создать массив объектов класса c
Перейти к содержимому

Как создать массив объектов класса c

Как объявить массив объектов в C#

у меня с самого начала вопрос. Предположим, у меня есть класс GameObject и я хочу создать массив GameObject объекты. Я мог бы написать код, например:

компилятор жалуется (предполагая из-за недопустимого синтаксиса). Поскольку это развитие XNA, я загружаю свою текстуру в LoadContent() метод следующим образом:

здесь houses[0] должно быть GameObject и может быть загружен так, но компилятор выдает эту ошибку:

» используйте ключевое слово » new «для создания экземпляра объекта»

«проверьте, чтобы определить, является ли объект null перед вызовом метода»

там должно быть что-то не так с моей инициализации.

7 ответов

проблема здесь в том, что вы инициализировали свой массив, но не элементов; все они равны нулю. Поэтому, если вы попытаетесь ссылаться houses[0] , будет null .

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

тогда вы можете инициализировать свой houses массив as:

вы создаете массив null ссылки. Вы должны сделать что-то вроде:

С LINQ, вы можете преобразовать массив неинициализированных элементов в новую коллекцию созданных объектов с одной строкой кода.

На самом деле, вы можете использовать любой другой источник для этого, даже сгенерированной последовательности целых чисел:

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

Я думаю GameObject является ссылочным типом. По умолчанию для ссылочных типов значение null => у вас есть массив нулей.

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

только тогда вы сможете получить доступ к объекту без ошибок компиляции.

таким образом, вы можете явно инициализировать массив:

или вы можете изменить GameObject ввести значение.

вы должны инициализировать элементы массива.

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

все, что у вас есть, выглядит нормально.

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

причина этого заключается в том, что инициализация массива не инициализирует каждый элемент в этом массиве. Вам нужно сначала установить houses[0] = new GameObject() и тогда это будет работать.

Массивы

XYZ School

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

Массивами в C# можно пользоваться практически так же, как и в других языках программирования. Тем не менее у них имеется одна особенность: они реализованы в виде объектов.

Для тoго чтобы воспользоваться массивом в программе, требуется двухэтапная процедура, поскольку в C# массивы реализованы в виде объектов. Во-первых, необходимо объявить переменную, которая может обращаться к массиву. И во-вторых, нужно создать экземпляр массива, используя оператор new.

Следует иметь в виду, что если массив только объявляется, но явно не инициализируется, каждый его элемент будет установлен в значение, принятое по умолчанию для соответствующего типа данных (например, элементы массива типа bool будут устанавливаться в false, а элементы массива типа int — в 0).

Инициализация массива

Помимо заполнения массива элемент за элементом (как показано в предыдущем примере), можно также заполнять его с использованием специального синтаксиса инициализации массивов. Для этого необходимо перечислить включаемые в массив элементы в фигурных скобках < >. Такой синтаксис удобен при создании массива известного размера, когда нужно быстро задать его начальные значения:

Обратите внимание, что в случае применения синтаксиса с фигурными скобками размер массива указывать не требуется (как видно на примере создания переменной myArr), поскольку этот размер автоматически вычисляется на основе количества элементов внутри фигурных скобок. Кроме того, применять ключевое слово new не обязательно (как при создании массива info).

Неявно типизированные массивы

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

Неявно типизированные массивы

Разумеется, как и при создании массива с использованием явного синтаксиса C#, элементы, указываемые в списке инициализации массива, должны обязательно иметь один и тот же базовый тип (т.е. должны все быть int, string или MyCar).

Определение массива объектов

В большинстве случаев при определении массива тип элемента, содержащегося в массиве, указывается явно. Хотя на первый взгляд это выглядит довольно понятно, существует одна важная особенность. В основе каждого типа в системе типов .NET (в том числе фундаментальных типов данных) в конечном итоге лежит базовый класс System.Object. В результате получается, что в случае определения массива объектов находящиеся внутри него элементы могут представлять собой что угодно:

Массив объектов

Свойство Length

Реализация в C# массивов в виде объектов дает целый ряд преимуществ. Одно из них заключается в том, что с каждым массивом связано свойство Length, содержащее число элементов, из которых может состоять массив. Следовательно, у каждого массива имеется специальное свойство, позволяющее определить его длину.

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

Как создать массив объектов класса c

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

Иллюстрация

Содержание

Объявление массива в C/C++

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

В C++ массивы статичны: вы не сможете изменить размер или тип элементов после объявления.

Доступ к элементам массива

Вы можете получать доступ к элементам массива, используя индексы и оператор [] . Допустим, вы объявили массив marks , как показано ниже. К первому элементу можно обратиться выражением marks[0] , ко второму — выражением marks[1] , и так далее. Доступ всегда начинается с единицы, а индекс последнего элемента на единицу меньше размера массива.

Иллюстрация

Инициализация массива при объявлении

Можно инициализировать массив при объявлении. Для этого надо указать в списке столько значений, сколько вмещает массив, либо одно значение 0, чтобы заполнить массив нулями:

Обход элементов массива в цикле

Узнать число элементов в массиве можно функцией std::size. Обойти можно, используя цикл по индексам либо range-based for:

Неопределённое поведение: выход за границы (out of bounds)

Выход за пределы массива является неопределённым поведением (англ. undefined behavior). Нет гарантий, как поведёт себя программа в этом случае. Высока вероятность, что вы испортите память других переменных, но эффект может различаться в разных режимах компиляции:

Передача массива как параметра функции

Массив в стиле языка C хранит только указатель на начало и не хранит свой размер, что и создаёт сложность в передаче в функцию. Размер массива известен во время компиляции, но не известен во время выполнения. Поэтому передать размер можно несколькими не очень очевидными путями:

Динамически изменяемый массив

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

Так мог бы выглядеть имитация динамического массива:

Класс std::vector<T>

Стандартная библиотека C++ содержит шаблонный класс vector, который работает как динамический массив произвольного размера. Размер может расти до тех пор, пока у операционной системы есть область памяти подходящего размера (вплоть до нескольких гигабайт).

Класс является шаблонным, то есть при объявлении переменной потребуется параметризовать шаблон класса vector типом элемента:

Использование вектора похоже на использование массива:

  • работает запрос элемента ages[index] , причём индексация так же начинается с нуля
  • при выходе за границы динамического массива так же возникает неопределённое поведение (англ. undefined behavior)
  • работает перебор элементов с помощью индексов, range-based for или итераторов
  • есть метод size для получения размера: ages.size()

Добавление элементов в конец массива

Для добавления существует два метода: push_back и emplace_back

  • push_back получает значение элемента и добавляет в конец
  • emplace_back работает сложнее: он получает параметры, необходимые конструктору элемента, и конструирует его прямо в конце массива

Вы можете практически всегда использовать push_back. Метод pop_back можно использовать для удаления элемента:

В документации std::vector можно прочитать о других методах.

Перемещение элементов в памяти при изменении массива

Динамический массив использует для хранения элементов динамическую память (так же известную как “куча”, англ. heap). При добавлении большого числа элементов динамический массив несколько раз перераспределяет память, поскольку выделенной ранее линейной области памяти уже не хватает для хранения всех элементов. Обычно при нехватке памяти под очередной элемент vector запрашивает новую область памяти в 1,5-2 раза больше предыдущей, перемещает в неё уже существующие элементы и добавляет в конец новый, а затем освобождает старую область памяти.

Если не сообразили, как это происходит, взгляните на картинку:

Иллюстрация

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

Метод erase для удаления элементов из середины

Метод erase класса vector получает итератор и уничтожает элемент, на который итератор указывает:

Последствия перемещения элементов: ошибка в простом цикле с erase

Использование итератора, ссылки или указателя на элемент после перераспределения памяти в массиве является неопределённым поведением: скорее всего произойдёт падение программы либо будет пропущено несколько элементов коллекции. Это показано в примере ниже:

Если вы запустите этот код, вы можете увидеть что угодно. Скорее всего программа выведет 10 38 99 , хотя должна вывести 10 23 7 38 99 по замыслу автора.

Для решения этой проблемы метод erase возвращает новый, валидный итератор на элемент, следующий после удалённого. Если элемент был последним, erase вернёт итератор end. Учитывая это, мы можем исправить код, чтобы новое значение it либо получалось из erase, либо получалось путём инкремента:

Программа корректно напечатает 10 23 7 38 99 .

Идиома remove_if + erase

В C++ есть замечательная библиотека алгоритмов <algorithm> . В данном случае алгоритмом называют шаблон функции, способный заменить цикл в какой-то одной узкой задаче. Например, remove_if перемещает элементы, соответствующие условию, в конец массива (в “удалённую” зону), и возвращает итератор на начала “удалённой” зоны. Затем вызовом erase можно уничтожить элементы из этой зоны.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *