Какая функциональность является «приемлемой» для структуры C ++? - PullRequest
16 голосов
/ 17 марта 2009

Мой первый пост, поэтому, пожалуйста, будьте осторожны!

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

Теперь это нормально, но с какого момента вы начинаете думать, что что-то уже не просто структура и должно стать классом?

Вещи, которые я считаю разумными для структур:

  1. конструкторы только с простым кодом инициализации.
  2. код сериализации, например операторы вставки / извлечения потока.

Вещи, в которых я не так уверен, но, вероятно, сделаю:

  1. операторы сравнения
  2. Простые функции преобразования - например, байтовая выгрузка всех элементов после получения данных из внешнего источника.

Я не думаю, что структуры должны иметь:

  1. динамическое выделение памяти.
  2. деструктор.
  3. сложные функции-члены.

Где лежат границы ???

Кроме того, разумно ли иметь экземпляры классов в качестве членов структуры? например,

class C {private: int hiddenData; public: void DoSomething();};

struct S {int a; float b; C c; };

S s; s.c.DoSomething();

Помните, я не о том, что вы МОЖЕТЕ делать с C ++, мне интересно, что вы ДОЛЖНЫ делать при разработке хорошего программного обеспечения.

Мысли

Ответы [ 19 ]

13 голосов
/ 17 марта 2009

Я думаю, что есть три основные, последовательные школы мысли:

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

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

(Кстати, в Lite C ++ FAQ есть довольно хорошее определение POD ).

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

10 голосов
/ 17 марта 2009

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

9 голосов
/ 17 марта 2009

Класс против структуры

Использование ключевого слова class или struct - дело вкуса вместе с '1005 * чувство ', которое оно производит на читателя. Технически они эквивалентны, но удобочитаемость лучше, если структуры используются для POD, а типы и классы C-struct для чего-либо еще.

Основные вещи, которые должны идти в конструкторе C ++ struct:, который инициализирует данные (мне не нравится использование 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 } };

Методы-члены и свободные функции

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

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

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

   // 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 +
   }

В приведенном выше коде, если operator + был методом-членом std :: string, компилятор не смог бы скомпилировать, поскольку он не может преобразовать литерал const char * в std :: string для использования метода member.

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

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

3 голосов
/ 17 марта 2009

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

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

3 голосов
/ 17 марта 2009

Вы можете посмотреть, что делает стандартная библиотека. Всеми любимая структура std :: pair имеет только конструкторы.

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

3 голосов
/ 17 марта 2009

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

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

2 голосов
/ 17 марта 2009

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

  1. Конструктор по умолчанию для инициализации членов данных известными значениями.
  2. Конструктор с одним параметром для каждого члена.
  3. оператор <, для легкого включения в наборы и карты. </li>
  4. оператор ==.
2 голосов
/ 17 марта 2009

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

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

1 голос
/ 04 февраля 2010

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

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

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

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

Лично я (сверх) использую ключевое слово struct для metafunctions

1 голос
/ 17 марта 2009

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

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

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

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

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