структура не принадлежит объектно-ориентированной программе - PullRequest
5 голосов
/ 31 октября 2008

Или это?

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

РЕДАКТИРОВАТЬ: Один из респондентов упомянул, что если нет инварианта, можно использовать структуру. Это интересное наблюдение: структура - это структура данных, то есть она содержит связанные данные. Если члены данных в структуре связаны, разве не всегда есть инвариант?

Ответы [ 17 ]

18 голосов
/ 31 октября 2008

В C ++ struct s и class es идентичны, за исключением общедоступных / закрытых по умолчанию их членов. (Это значение по умолчанию легко и обычно переопределяется.)

Однако большинство программистов считают структуру «объектом данных», а класс - «интерактивным объектом». Это не плохо; и на самом деле следует воспользоваться. Если что-то представляет собой просто неодушевленный кусок данных (даже, может быть, если у него есть пара методов инспектора), используйте для него структуру; это сэкономит немного усилий, когда программист попытается понять, для чего он нужен.

13 голосов
/ 31 октября 2008

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

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

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

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

4 голосов
/ 31 октября 2008

В C ++ различие между структурой и классом заключается в видимости по умолчанию его содержимого (то есть public для структуры и private для класса). Я предполагаю, что эта разница заключалась в том, чтобы сохранить совместимость с C.

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

Пример структуры

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

struct CPoint
{
   int x ;
   int y ;

   CPoint() : x(0), y(0) {}

   int getDistanceFromOrigin() const
   {
      return std::sqrt(x * x + y * y) ;
   }
} ;

inline CPoint operator + (const CPoint & lhs, const CPoint & rhs)
{
   CPoint r(lhs) ;
   r.x += rhs.x ;
   r.y += rhs.y ;
   return r ;
}

Вы можете изменить значение x для CPoint, и оно все еще остается действительным CPoint.

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

Пример класса

В классе все является закрытым (по умолчанию), что означает, что пользователь может изменять данные только через четко определенный интерфейс, поскольку класс должен сохранять свои внутренние данные действительными. Пример класса:

class CString
{
   public :
      CString(const char * p) { /* etc. */ } ;
      CString(const CString & p) { /* etc. */ } ;

      const char *     getString() const { return this->m_pString ; }
      size_t           getSize() const { return this->m_iSize ; }

      void             copy { /* code for string copy */ }
      void             concat { /* code for string concatenation */ }

   private :
      size_t           m_iSize ;
      char *           m_pString ;
} ;

inline CString operator + (const CString & lhs, const CString & rhs)
{
   CString r(lhs) ;
   r.concat(rhs) ;
   return r ;
}

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

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

Заключение

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

Если каждый фрагмент данных независим от всех остальных, то, возможно, вам следует рассмотреть структуру (т. Е. Класс с открытым элементом данных).

Если нет, или, если сомневаетесь, используйте класс.

Теперь, конечно, в C # структура и класс - это два разных типа объектов (то есть типы значений для структур и ссылочные типы для классов). Но это не из этой темы, я думаю.

4 голосов
/ 31 октября 2008

В C #, например, я использую структуры для некоторых простых типов данных с лучшим значением слева:

public struct Point
{
    int X;
    int Y;
}

и для любого P / Invoke в библиотеки, где аргументы являются структурами, вам придется использовать их наверняка.

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

2 голосов
/ 31 октября 2008

Технически, структура - это класс с видимостью public по умолчанию (реальный класс имеет видимость private по умолчанию).

Существует больше различий в общем использовании.

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

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

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

2 голосов
/ 10 ноября 2008

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

Если ваш struct является просто совокупностью различных объектов и не имеет инварианта для хранения, вы действительно свободны и поощряете помещать его членов public. Именно так std::pair<T, U> в C ++ делает это.

Что это за инвариант? Простой пример. Предположим, у вас есть класс Point, члены которого x and y всегда должны быть >= 0. Вы можете сделать инвариант с указанием /* x >= 0 && y >= 0 for this classes' objects. */ Если вы теперь сделаете этих членов публичными, клиенты могут просто изменить x и y, и ваш инвариант может легко сломаться. Однако если членам разрешено содержать все возможные значения, соответствующие их собственным инвариантам соответственно, вы, конечно, можете просто сделать эти члены общедоступными: вы все равно не добавите им никакой защиты.

1 голос
/ 31 октября 2008

Структура по сути является классом модели, но с другим синтаксисом.

public struct Point {
    int x;
    int y;
}

логически совпадает с:

public class Point {
    private int x;
    private int y;
    public void setX(int x) { this.x=x; }
    public int getX(); { return x; }
    public void setY(int y) { this.y=y; }
    public int getY(); { return y; }
}

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

0 голосов
/ 05 ноября 2008

Смотрите эти похожие вопросы:

Когда вы должны использовать класс против структуры в C ++?

Каковы различия между структурой и классом в C ++

плюс:

Согласно Страуструпу на языке программирования C ++ :

Какой стиль вы используете, зависит от обстоятельств и вкуса. Я обычно предпочитаю использовать struct для классов, в которых все данные являются открытыми. Я думаю о таких классах как «не совсем правильные типы, просто структуры данных».

0 голосов
/ 31 октября 2008

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

0 голосов
/ 31 октября 2008

Структура, используемая в C или C ++, и структура, используемая в C # (или любом языке .Net), - это такие разные животные, что они, вероятно, даже не должны иметь одно и то же имя ... Практически любое обобщение структур на одном языке может легко быть ложным, или верным по совершенно не связанной причине, на другом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...