Правила программирования на Си и Си++

       

Используйте структуры только тогда, когда все данные открытые и нет функций-членов


Это правило является вариантом принципа "если это похоже на Си, то должно и действовать как Си". Используйте структуры, только если вы делаете что-то в стиле Си.

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

typedef struct

tagSIZE    // Существующее определение из

                          // заголовочного файла Си

{

   LONG  cx;

   LONG  cy;

}

SIZE;

class CSize : public SIZE // Определение в файле Си++

{

   // ...

}

Я видел определения классов, подобные следующему, где требуется доступ к полям cx и cy

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

высоты. Например:

CSize some_size;

   some_size.cy;                 // тьфу!

Вы должны иметь возможность написать:

some_size.height();

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



Содержание раздела