Сколько функциональности “приемлемо” для структуры C++?

Вы должны прочитать (если у вас есть доступ) Эффективный Java 2 Пункт 1: Рассмотрите статические заводские методы вместо конструкторов.

Преимущества статических заводских методов:

  1. У них есть имена.
  2. Они не обязаны создавать новый объект при каждом вызове.
  3. Они могут возвращать объект любого подтипа своего возвращаемый тип.
  4. Они уменьшают многословие создания экземпляров с параметризованным типом.

Недостатки статических заводских методов:

  1. При предоставлении только статической фабрики методы, классы без публичных или защищенных конструкторов не могут быть подклассы.
  2. Они не могут быть легко различимы с другими статическими методами

16
задан Eclipse 17 March 2009 в 15:39
поделиться

19 ответов

Класс по сравнению со структурой

Используя класс или ключевое слово структуры является вопросом вкуса вместе с' чувство ', это производит на читателе. Технически они эквивалентны, но удобочитаемость лучше, если структуры используются для ПЕРЕХОДНЫХ ПРИСТАВОК и типов C-структуры и классов для чего-либо еще.

Основные вещи, которые должны войти в структуру C++: конструктор, который инициализирует данные (мне не нравится использовать memset, и он может позже воздержаться, если POD развивается во что-то другое), или конструкция от других типов, но не конструктора копии.

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

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

struct square_int {
   int operator()( int value )
   {
      return value*value;
   }
};
std::transform( v.begin(), v.end(), v.begin(), square_int() );

или

// off the top of my head
template <typename T>
struct is_pointer { enum { value = false } };

template <typename T>
struct is_pointer<T*> { enum { value = true } };

членские методы по сравнению с бесплатными функциями

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

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

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

   // Example of symmetry with free functions where method would be asymmetric
   int main()
   {
      std::string( "Hello " ) + "world"; // compiles as free / member function
      "Hello " + std::string( "world" ); // compiles with free function, fails with member function definition of +
   }

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

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

преобразования Хранения, поскольку бесплатные функции разъединяют эти два различных типов. Если A и' может быть преобразован друг в друга, и Вы решаете реализовать преобразования как члены A, то Необходимость знает', и все использование A будет зависеть от', используете ли Вы его или нет. Если Вы определяете преобразование как бесплатную функцию, A завершен без', и связь между этими двумя классами/структурами будет меньшей. То же идет, чтобы преобразования объединились в сеть, сериализация и десериализация. При реализации их в классе/структуре, Вы вынуждаете всех пользователей знать о тех преобразованиях.

9
ответ дан 30 November 2019 в 15:56
поделиться

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

Как показывает опыт, я буду обычно использовать структуры для более простых типов данных, располагающихся от ПЕРЕХОДНЫХ ПРИСТАВОК до объектов, которые имеют участника простые функции. Но нет никакой яркой строки, и как только я определяю структуру, я не буду обычно возвращаться и изменять ее на класс просто, потому что я добавил больше функциональности. Я не вижу значения в этом.

-1
ответ дан 30 November 2019 в 15:56
поделиться

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

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

Единственными исключениями были бы вещи, требуемые быть функциями членства для некоторой другой цели - конструкторы для инициализации массивов; сравнения для использования с картой; вещи используются шаблонами; и т.д.

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

Возвращение к примеру свопинга байта:

struct S
{
    int data;
    S() {data = 1234;}
    void ByteSwap() {network::ByteSwap( &data );}
};

S s;
s.ByteSwap();

стал бы:

struct S
{
    S() {data = 1234;}
    int data;
};

namespace network
{
    void ByteSwap( int* i ) {/*byte swap *i*/}
    void ByteSwap( S* s ) {ByteSwap( &s->data );}

    S s;
    ByteSwap(&s);
}

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

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

0
ответ дан 30 November 2019 в 15:56
поделиться

Мое простое эмпирическое правило для структур и классов:

if (data_requires_strict_alignment == TRUE) {
  use(struct);
} else {
  use(class);
}

таким образом, если данные Вы представляете, соответствует некоторому объекту данных, который сделал, чтобы строгий участник заказал и требования выравнивания (например, структура данных, которой обмениваются с аппаратными средствами на уровне драйвера), использовал структуру. Для всех других случаев используйте класс. Классы имеют столько функций и возможностей, которые не делают структуры, и в моих событиях выгодно использовать классы, когда это возможно, даже если Вы не используете ни одной из тех дополнительных функций в данный момент (если ничто иное, класс только для данных похож на структуру с более безопасным уровнем доступа по умолчанию). Зарезервируйте структуры для тех случаев при необходимости в уникальных свойствах структуры; а именно, способность определить элементы структуры в точном порядке и с точным выравниванием/дополнением (обычно с коммуникацией низкого уровня, например, драйверами) таким образом, что можно бросить его к массиву байтов, использование memcpy() на ней, и т.д. Если бы Вы следуете этой модели, тогда класс, не использовалась бы в качестве члена структуры (так как определение класса не определяет выравнивание или предсказуемое значение для sizeof(class)). Аналогично, если Вы думаете о конструкторах или операторах, используйте класс.

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

0
ответ дан 30 November 2019 в 15:56
поделиться

Обычно я использую class каждый раз, когда я должен использовать спецификаторы доступа. Это имеет эффект, которым большая часть моего материала верхнего уровня остается как классы, в то время как редкие наборы POD и мой not-so-rare внутренний класс pimpls обычно являются структурами.

0
ответ дан 30 November 2019 в 15:56
поделиться

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

0
ответ дан 30 November 2019 в 15:56
поделиться

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

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

0
ответ дан 30 November 2019 в 15:56
поделиться

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

Свойства

, Например, я мог бы определить RECT структура как указано ниже:

typedef struct tagRECT{
    int left;
    int top;
    int right;
    int bottom;

    int get_width(){return right - left;}
    int get_height(){return bottom - top;}
    int set_width(int width){right = left + width; return width;}
    int set_height(int height){bottom = top + height; return height;}
} RECT, *PRECT;

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

Простые преобразования

Для типов POD, которые хранят сложные данные, я мог бы включать методы, которые выполняют простые преобразования на тех данных. Очевидный пример мог бы включать, Вращаются, Масштаб, Сдвиг, и Переводят методы на структуре TransformationMatrix.

Операторы

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

Конструкторы

я предпочитаю не иметь конструктора по умолчанию на своих структурах. Я не хочу выделять массив ПЕРЕХОДНЫХ ПРИСТАВОК и переносить вызов тысячи (или безотносительно) инициализации по умолчанию. Если memset инициализация не будет достаточна, я предоставлю Инициализировать метод.

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

0
ответ дан 30 November 2019 в 15:56
поделиться

Если существуют accesser методы для элементов данных тогда, это - класс.

, Если Вы имеете прямой доступ к данным и можете изменить его по желанию, это - структура.

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

0
ответ дан 30 November 2019 в 15:56
поделиться

Другое общее использование структур для шаблонного материала и локального RAII или классов функтора. Это одноразовые биты кода, которые ближе к функциям, чем они к целым классам и требованию дополнительного public:, объявление просто глупо. При рассмотрении повышения Вы будете видеть много материала как это:

template<
      bool C
    , typename T1
    , typename T2
    >
struct if_c
{
    typedef T1 type;
};

Это - ясно не POD (на самом деле, это не содержит данных вообще). В других случаях у Вас может быть класс RAII, которые состоят только из constructor/desctructor:

struct LogOnLeavingScope : public NonCopyable
{
    string Message;
    LogOnLeavingScope(const string &message) : Message(message) {}
    ~LogOnLeavingScope() { Log(Message); }
];

классы Функтора предложили бы тот же аргумент:

struct Logger
{
    void operator()(const string &message) { Log(message); }
}

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

0
ответ дан 30 November 2019 в 15:56
поделиться

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

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

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

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

1
ответ дан 30 November 2019 в 15:56
поделиться

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

  1. конструктор по умолчанию А, для инициализации элементов данных к известным значениям.
  2. конструктор А с одним параметром для каждого участника.
  3. operator< для легкого включения в наборы и карты.
  4. оператор ==.
2
ответ дан 30 November 2019 в 15:56
поделиться

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

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

2
ответ дан 30 November 2019 в 15:56
поделиться

Вы могли посмотреть на то, что делает Стандартная Библиотека. Общая любимая структура станд.:: пара только имеет конструкторов.

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

3
ответ дан 30 November 2019 в 15:56
поделиться

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

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

3
ответ дан 30 November 2019 в 15:56
поделиться

От прочтения некоторого исходного кода STL, который поставлется с Visual Studio, кажется, что используемые критерии являются действительно ли вещами, "главным образом общедоступны" (запустите с структура ), или "главным образом частный" (запускаются с класс )?

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

3
ответ дан 30 November 2019 в 15:56
поделиться

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

10
ответ дан 30 November 2019 в 15:56
поделиться

Я думаю, что существует три главных, когерентных философских школы:

  1. Люди, которые не заботятся так или иначе и использование struct и class попеременно.
  2. Люди, которые используют struct с только для представления маленького POD.
  3. Люди, которые используют struct с в качестве записей.

я не могу привести окончательный аргумент в пользу ни одной из этих стратегий. Я склонен следовать за путем 2, но я также использую структуры для типов не-POD, когда я вижу, что он соответствует, специально для функциональных объектов (даже если они не могут выполнить требования POD).

(Кстати, облегченный FAQ C++ имеет довольно хорошее определение POD).

РЕДАКТИРОВАНИЕ я не коснулся шаблонных методов метапрограммирования, таких как использование struct для заполнителей (введите теги) или реализовать метафункции. Я предполагаю, что в этих случаях нет абсолютно никакого противоречия: так как они никогда не содержат методы (или даже данные), всегда используйте struct).

13
ответ дан 30 November 2019 в 15:56
поделиться

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

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

7.8 В чем разница между ключевыми словами struct и классом?

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

Лично я (более)использую struct ключевое слово для метафункций

1
ответ дан 30 November 2019 в 15:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: