структура и класс в чем разница c

Выбор между классом и структурой

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

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

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

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

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

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

Как правило, большинство типов в платформе должны быть классами. Однако существуют ситуации, в которых характеристики типа значения делают более подходящим использование структур.

✔️ Рассмотрите возможность определения структуры вместо класса, если экземпляры типа небольшие и часто используются кратковременно или обычно внедряются в другие объекты.

❌ НЕ следует определять структуру, если тип имеет не все приведенные ниже характеристики.

Он имеет размер экземпляра менее 16 байт.

Он не должен быть часто в штучной упаковке.

Во всех остальных случаях типы следует определять как классы.

Части © 2005, 2009 Корпорация Майкрософт. Все права защищены.

Источник

Классы или структуры, в чем отличия

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

Структуры синтаксически очень похожи на классы, но существует принципиальное отличие, которое заключается в том, что класс – является ссылочным типом (reference type), а структуры – значимым типом (value type) (см. статью «Типы данных«). Следовательно, классы всегда создаются в так называемой “куче” (heap), а структуры создаются в стеке (stack).

Но это справедливо в очень простых случаях, главное отличие структур и классов: структуры, указываемые в списке параметров метода, передаются по значению (то есть копируются), объекты классов — по ссылке. Именно это является главным различием в их поведении, а не то, где они хранятся. Примечание: структуру тоже можно передать по ссылке, используя модификаторы out и ref.

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

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

Мы выяснили, что все встроенные типы значений задаются структурами, например, числовые типы int, long, float определены структурами System.Int32, System.Int64 и System.Single соответственно. Эти структуры имеют поля и методы. Мы уже вызывали методы у переменных этих типов. Например, каждая из перечисленных структур имеет метод ToString( ). Также у перечисленных структур есть статичные поля, например, Int32.MaxValue или Int32.MinValue. Получается, что мы уже многократно использовали структуры.

В отличие от классов, использование публичных полей в структурах в большинстве случаев не рекомендуется, потому что не существует способа контролирования значений в них. Например, кто-либо может установить значение минут или секунд более 60. Более правильный вариант в данном случае использовать свойства, а в конструкторе осуществить проверку:

В результате будет напечатано число часов: 6 (остаток от деления 30 на 24).
Заменим конструктор Time(…) конструктором без параметров:

Получим сообщение об ошибке:
«Структуры не могут содержать явных конструкторов без параметров»

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

Что же касается класса, то компилятор создает конструктор по умолчанию только в том случае, если Вы его не создали. При объявлении класса нет проблем создать собственный конструктор без параметров (замените в программе ключевое слово struct на class, вы получите результат — 7).

Еще один эксперимент. Замените снова class на struct и удалите полностью конструктор Time(). Запустите программу, она будет выполнена, результат – 0. Вы получите три предупреждения типа:
«Полю «ConsoleApplication1.Time.hours» нигде не присваивается значение, поэтому оно всегда будет иметь значение по умолчанию 0».

Это означает, что был сгенерирован конструктор (без параметров) для структуры, который всегда устанавливает поля в 0, false или null (для объектов) – как и для классов. Поэтому Вы можете быть уверенными в том, что созданная структура всегда будет вести себя адекватно в соответствии со значениями по умолчанию в используемых типах.

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

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

Два правила структур

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

Второе правило структуры: Нельзя инициализировать переменные в том месте, где они объявляются.

Сравнение классов и структур в сжатом виде:

ВопросСтруктураКласс
Какого же типа экземпляр объекта?Значимый (value) типСсылочный (reference) тип
Где “живут” экземпляры этих объектов?Экземпляры структуры называют значениями и “живут” они в стеке (stack).Экземпляры классов называют объектами и “живут” они в куче (heap).
Можно ли создать конструктор по умолчанию?НетДа
Если создается свой конструктор, будет ли компилятор генерировать конструктор по умолчанию?ДаНет
Если в своём конструкторе не будут инициализированы некоторые поля, будут ли они автоматически инициализированы компилятором?НетДа
Разрешается ли инициализировать переменные там, где их объявляют?НетДА

Поля структуры могут быть инициализированы при использовании конструктора (если объект объявляется с помощью оператора new), причем не важно, какого «собственного» или «по умолчанию».

К особенностям структур можно отнести еще и тот факт, что вследствие того, что структуры являются значимым типом, то можно создать структуру без использования конструктора, например:

В таком случае, переменная t создается, но поля не будут инициализированы конструктором (нет оператора Time t = new Time();). Правда, теперь поля структуры придется объявлять только с модификатором public.

Замечания, над которыми стоит подумать (проверить практикой):

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

2. Дополнения: структуры не могут быть абстрактными, структуры не имеют деструкторов, структуры не поддерживают наследование.

3. Главное отличие структур и классов: структуры передаются по значению (то есть копируются), объекты классов — по ссылке. Именно это является существенным различием в их поведении, а не то, где они хранятся.

4. Структуру тоже можно передать по ссылке, используя модификаторы out и ref.

Ответ: 400016 байт. Конец примечания.

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

Источник

C# NET: Class vs Struct или в чём различия между Классом и Структурой

Просто о NET | создано: 10.07.2011 | опубликовано: 10.07.2011 | обновлено: 27.12.2021 | просмотров: 92733 | комментариев: 30

Мне в последнее время очень часто встречаются программисты, которые не только используют в обычной “программной” жизни структуры (struct), но вообще, ничего не знают об этом объекте. И зачастую, для простоты своей «программной» жизни используют всегда классы (class). В этой статье я бы хотел в очередной раз остановиться на различиях между структурами и классами.

Что такое struсture?

Ключевой момент статьи: Чем больше Вы будете использовать структуры вместо небольших (наверное, правильнее будет сказать – маленьких) классов, тем менее затратным по ресурсам будет использование памяти. Смею предположить, что не требуется объяснения почему… “куча”, “сборщик мусора”, “неопределенные временные интервалы прохода”, сложность “ручного” управления кучей и сборщиком мусора. Все ключевые моменты уже перечислены.

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

Структуры всегда с ВамиНе хочется думать, что следующая информация, для Вас сюрпризом. В языке C# примитивные числовые типы int, long, float являются альясами для структур System.Int32, System.Int64 и System.Single соответственно. Эти структуры имеют поля и методы. Вы обычно вызываете методы у переменных данных типов. Например, каждая из перечисленных структур имеет метод ToString. Также у перечисленных структур есть статичные поля, например, Int32.MaxValue или Int32.MinValue. Получается, что Вы уже в повседневной «программной» жизни используете структуры, а значит знакомы с ними.

Таблица классов и структур в Microsoft. NET Framework

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

KeywordType equivalentClass or structure
boolSystem.BooleanStructure
byteSystem.ByteStructure
decimalSystem.DecimalStructure
doubleSystem.DoubleStructure
floatSystem.SingleStructure
intSystem.Int32Structure
longSystem.Int64Structure
objectSystem.ObjectClass
sbyteSystem.SByteStructure
shortSystem.Int16Structure
stringSystem.StringClass
uintSystem.UInt32Structure
ulongSystem.UInt64Structure
ushortSystem.UInt16Structure

Объявление структур

Для объявления структуры используется зарезервированное слово struct, следом наименование структуры и фигурные скобки:

Кстати, …По умолчанию, Вы не можете использовать некоторые общие операторы в Ваших структурах. Например, Вы не можете использовать оператор сравнения (==) и противоположные ему (!=) на своих структурах. Однако, Вы можете явно объявить и реализовать операторы для своих структур.

И в чем же разница между структурами и классами

Давайте рассмотрим пример, в котором уже заложена ошибка:

Причина возникновении ошибки в том, что Вы не можете использовать конструктор по умолчанию (без параметров) для структуры, потому что компилятор всегда генерирует его сам. Что же касается класса, то компилятор создает конструктор по умолчанию, только в том случае, если Вы его не создали. Сгенерированный конструктор для структуры всегда устанавливает поля в 0, false или null – как и для классов. Поэтому Вы можете быть уверенными в том, что созданная структура всегда будет вести себя “адекватно” в соответствии со значениями по умолчанию в используемых типах. Если Вы не хотите использовать значения по умолчанию, Вы можете инициализировать поля своими значениями в конструкторе с параметрами для инициализации. Однако, если в этом конструкторе не будет инициализировано какое-нибудь значение, компилятор не будет его инициализировать за Вас и покажет ошибку.

Первое правило Структуры: Всегда все переменные должны быть инициализированы!

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

Второе правило Структуры: Нельзя инициализировать переменные в месте их объявления!

Данная таблица в некотором роде подытоживает всё вышесказанное и отображает основные отличия между классами и структурами.

ВопросСтруктураКласс
И какого же типа экземпляр объекта?Структура значимый (value) типКласс ссылочный (reference) тип
А где “живут” экземпляры этих объектов?Экземпляры структуры называют значениями и “живут” они в стеке (stack).Экземпляры классов называют объектами и “живут” они в куче (heap).
Можно ли создать конструктор по умолчанию?НетДа
Если создается свой конструктор будет ли компилятор генерировать конструктор по умолчанию?ДаНет
Если в своём конструкторе не будут инициализированы некоторые поля, будут ли они автоматически инициализированы компилятором?НетДа
Разрешается ли инициализировать переменные в месте их объявления?НетДа

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

После того как Вы создали структуры, Вы можете использовать ее также как классы и другие типы. Например, создав структуру Time, я могу использовать ее в классе:

Вы можете создавать nullable версию переменной типа структуры использую модификатор “?” и потом присвоить ей значение null:

Time? currentTime = null;

Инициализация структур

В статье я не раз говорил, что поля структуры могут быть инициализированы при использования конструктора, причем не важно какого “собственного” или “по умолчанию”. К особенностям структур можно отнести еще и тот факт, что вследствие того, что структуры являются значимым типом, то можно создать структуру без использования конструктора, например:

В таком случае, переменная создается, но поля не будут инициализированы в соответствии параметрами конструктора.

Заключение

Используйте структуры, это признак хорошего тона в программировании на C# и да прибудет с Вами сила… структур. Цитата из комментария: «С заключением тоже не согласен. Многие маститые западные авторы наоборот рекомендуют как можно меньше использовать структуры, предпочитая классы. Хотя, конечно, молиться на них и их мнение не стоит, лучше думать своей головой.»

Источник

Объектно-ориентированное программирование

Инкапсуляция

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

Участники

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

Специальные возможности

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

Наследование

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

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

Интерфейсы

Классы, структуры и записи могут реализовывать несколько интерфейсов. Реализация из интерфейса означает, что тип реализует все методы, определенные в интерфейсе. Дополнительные сведения см. в статье Интерфейсы.

Универсальные типы

Статические типы

Вложенные типы

Класс, структура или запись могут быть вложены в другой класс, структуру или запись.

Разделяемые типы

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

Инициализаторы объектов

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

Анонимные типы

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

Методы расширения

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

Неявно типизированные локальные переменные

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

Записи

Дополнительные сведения см. в статье Записи.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

Источник

Структура ИЛИ класс. Поясняющие примеры

В статье «Классы или структуры, в чем отличия» приведены небольшие примеры, которые, как показал опыт общения с начинающими программистами, недостаточны для более глубокого понимания этих различий. Поэтому будет полезно рассмотреть еще примеры.
Ключевое слово здесь, как предлагает в комментариях Руслан, альтернатива (структура или класс), т.е. когда что выбирать. Рекомендую обязательно эксперименты проводить в среде VS (не теоретически — лучше поймете!).

Эксперимент №1.

Для быстрого анализа в тексте примера 1 (файл Class2.cs) заменим только строку public class MFC на public struct MFC и запустим проект.
Получим 6 сообщений об ошибках:

Анализ:
1) Первые три ошибки связаны с объявлением методов GetChild(), Output(), Tir() как virtual.
Вывод: модификатор virtual к методам структур не применим. Тем не менее, модификатор public имеет в структуре то же назначение, что и в классе — обеспечить доступ к данным.
2) Другие три ошибки связаны с объявлением в нашей структуре MFC полей mother; father; child с модификатором protected (в классе мы их так объявили, так как предполагали их защиту и наследование, см. Пример 2).
Вывод:
Удалим модификатор protected, тем самым тип этих полей станет private (по умолчанию). Конечно, можно было бы явно вместо protected указать public, однако это будет неверно с позиций защиты данных.
Удалим лишнее, тогда получим в файле Class2.cs:

Текст файла Program.cs оставим без изменений:

Результат:

В точном соответствии с Примером 1 на базе класса MFC. При необходимости разберите его отдельно.

Эксперимент 2.

Что произойдет, если мы удалим (удобнее просто пока закомментировать) конструктор public MFC(string m, string f, string c) < >.
Результат компиляции:

Конечно понятна причина, в Main() имеется оператор MFC R = new MFC(«Барбара», «Борис», «Бэлла»);, предполагающий создание экземпляра структуры с конкретными значениями полей.
Если так нельзя, то попробуем задать для структуры конструктор без параметров, например такой:

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

Соответственно в Main() оператор MFC R = new MFC(«Барбара», «Борис», «Бэлла»); заменим на MFC R = new MFC();.
Результат компиляции:

Вывод 1: Для структур нельзя создать конструктор по умолчанию (без параметров).

А если выполнить обратную замену? Вместо struct напишем снова class? Тогда все замечательно, ошибок нет, результат проверки:

Вывод 2: Для класса создание конструктора без параметров вполне допустимо.

Эксперимент №3.

Если в последнем случае (с классом) вообще удалим конструктор класса MFC. Тогда при выполнении оператора MFC R = new MFC(); объект будет все таки создан, но с пустыми полями (так как они типа string, то их значения = null). И вот результат:

Вывод. Если конструктор в описании класса отсутствует, то он по умолчанию все таки создается, равно как и полям объекта присваиваются начальные значения.

Итоги экспериментов:

Сравните эти выводы с таблицей, где сравниваются классы и структуры, см. «Классы или структуры, в чем отличия».

Источник

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

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