Используйте структуры только тогда, когда все данные открытые и нет функций-членов
Это правило является вариантом принципа "если это похоже на Си, то должно и действовать как Си". Используйте структуры, только если вы делаете что-то в стиле Си.
Следует также избегать наследования от структуры. Даже если мне многое не удалось изложить четко, надеюсь, что я прояснил смысл тезиса "закрытые данные или никакие". Зная о проблемах с прямым доступом к открытым данным, вы можете понять, почему следующее не является очень хорошей идеей:
typedef struct
tagSIZE // Существующее определение из
// заголовочного файла Си
{
LONG cx;
LONG cy;
}
SIZE;
class CSize : public SIZE // Определение в файле Си++
{
// ...
}
Я видел определения классов, подобные следующему, где требуется доступ к полям cx и cy
базового класса через указатель производного класса для того, чтобы определить соответствующее им значение третьей координаты —
высоты. Например:
CSize some_size;
some_size.cy; // тьфу!
Вы должны иметь возможность написать:
some_size.height();
У предшествующего кода есть другая, более трудно уловимая проблема. Наследование от существующей структуры Си часто выполняется программистом, который верит, что сможет передать объект Си++ в существующую функцию Си. То есть программист полагает, что раз наследование фактически добавляет поля к базовому классу, то производный класс в буквальном смысле будет расположен точно так же, как и базовый класс, но с присоединением нескольких дополнительных полей. Однако, это может быть и не так. Если производный класс добавляет, например, виртуальную функцию, то в базовый класс может быть добавлен указатель на таблицу виртуальных функций. Аналогично, если производный класс использует множественное наследование одновременно от структуры Си и чего-то еще, то нет никакой гарантии, что структура Си будет в начале.