По аналогии, C # в основном похож на набор инструментов механика, где кто-то прочитал, что обычно следует избегать плоскогубцы и разводные ключи, поэтому он вообще не включает разводные ключи, а плоскогубцы запираются в специальном ящике с надписью «небезопасно» и может быть использован только с разрешения супервайзера после подписания заявления об отказе от ответственности, которое освобождает вашего работодателя от ответственности за ваше здоровье.
C ++, для сравнения, включает не только разводные ключи и плоскогубцы, но и некоторые довольно необычные инструменты специального назначения, назначение которых не сразу понятно, и если вы не знаете, как правильно их держать, они могут легко отрезать вам большой палец (но как только вы поймете, как их использовать, можете делать вещи, которые по сути невозможны с помощью основных инструментов в наборе инструментов C #). Кроме того, у него есть токарный станок, фрезерный станок, плоскошлифовальный станок, ленточная пила для резки металла и т. Д., Позволяющие проектировать и создавать совершенно новые инструменты в любое время, когда вы чувствуете необходимость (но да, инструменты этих машинистов могут и будут вызывать серьезные травмы, если вы не знаете, что вы делаете с ними - или даже если вы просто неосторожны).
Это отражает основное различие в философии: C ++ пытается предоставить вам все инструменты, которые вам могут понадобиться, по существу, для любого дизайна, который вам может понадобиться. Он практически не пытается контролировать использование этих инструментов, поэтому их легко использовать для создания проектов, которые хорошо работают только в редких ситуациях, а также проектов, которые, вероятно, являются просто паршивой идеей, и никто не знает о ситуации, в которой они, скорее всего, будут хорошо работать. В частности, многое из этого достигается путем разделения дизайнерских решений - даже тех, которые на практике действительно почти всегда связаны. В результате между написанием C ++ и написанием C ++ существует огромная разница. Чтобы хорошо писать на C ++, вам нужно знать много идиом и практических правил (включая практические правила о том, как серьезно пересмотреть, прежде чем нарушать другие эмпирические правила). В результате, C ++ больше ориентирован на простоту использования (экспертами), чем на простоту обучения. Есть также (слишком много) обстоятельства, при которых это не очень просто использовать.
C # делает гораздо больше, чтобы попытаться (или, по крайней мере, чрезвычайно убедительно) предложить то, что разработчики языка считают хорошими практиками проектирования. Многие вещи, которые в C ++ отделены (но обычно на практике встречаются вместе), напрямую связаны в C #. Это позволяет «небезопасному» коду немного расширять границы, но, честно говоря, не очень.
В результате, с одной стороны, существует довольно много дизайнов, которые можно выразить довольно прямо в C ++, которые существенно неуклюжи для выражения в C #. С другой стороны, это целое намного легче выучить C #, и шансы получения действительно ужасный дизайн , который не будет работать для вашей ситуации (или , возможно , любой другой) являются резко снижается. Во многих (возможно, даже в большинстве) случаях вы можете получить надежный, работоспособный дизайн, просто, так сказать, «плывя по течению». Или, поскольку один из моих друзей (по крайней мере, мне нравится думать о нем как о друге - не уверен, действительно ли он согласен) любит это выражать, C # позволяет легко попасть в пропасть успеха.
Итак, более подробно рассмотрев вопрос о том, как class
и struct
как они появились на двух языках: объектах, созданных в иерархии наследования, где вы можете использовать объект производного класса под видом его базового класса / интерфейса, вы в значительной степени застряв в том факте, что вам обычно нужно делать это с помощью какого-то указателя или ссылки - на конкретном уровне происходит то, что объект производного класса содержит что-то в памяти, что можно рассматривать как экземпляр базового класса / интерфейс, и производным объектом манипулируют через адрес этой части памяти.
В C ++ программист должен сделать это правильно - когда он использует наследование, он должен убедиться, что (например) функция, которая работает с полиморфными классами в иерархии, делает это с помощью указателя или ссылки на базу учебный класс.
В C # то, что по сути такое же разделение между типами, гораздо более явное и обеспечивается самим языком. Программисту не нужно предпринимать никаких шагов для передачи экземпляра класса по ссылке, потому что это произойдет по умолчанию.
struct
s не всегда хранятся в стеке; Рассмотрим объект сstruct
полем. Кроме того, как отметил Мейсон Уилер, проблема с нарезкой, вероятно, является главной причиной.