Структура объекта C ++ в памяти против структуры - PullRequest
44 голосов
/ 08 января 2009

Если у меня есть класс следующим образом

   class Example_Class 
   {
       private:
         int x; 
         int y; 
       public: 
         Example_Class() 
         { 
             x = 8;
             y = 9;
         }
       ~Example_Class() 
       { } 
   };

И структура выглядит следующим образом

struct
{
   int x;
   int y;
} example_struct;

Является ли структура в памяти example_struct аналогичной структуре в Example_Class

например, если я сделаю следующее

struct example_struct foo_struct;
Example_Class foo_class = Example_Class();

memcpy(&foo_struct, &foo_class, sizeof(foo_struct));

будет foo_struct.x = 8 и foo_struct.y = 9 (то есть: те же значения, что и значения x, y в классе foo_class)?

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

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

Ответы [ 8 ]

61 голосов
/ 08 января 2009

Стандарт C ++ гарантирует , что макеты памяти C struct и C ++ class (или struct - то же самое) будут идентичны при условии, что C ++ class / struct соответствует критерию POD («Обычные старые данные»). Так что же означает POD?

Класс или структура - это POD, если:

  • Все члены данных являются открытыми и сами являются POD или базовыми типами (но не ссылочными или указателями на элементы) или массивами таких
  • У него нет пользовательских конструкторов, операторов присваивания или деструкторов
  • У него нет виртуальных функций
  • не имеет базовых классов

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

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

Подробнее см. Раздел [26.7] C ++ Lite Lite .

10 голосов
/ 08 января 2009

Структура в памяти example_struct похожа на структуру в Example_Class

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

Сказав это, ответ "да, на моей машине", при условии, что Example_Class не содержит виртуального метода (и не наследует от базового класса).

7 голосов
/ 08 января 2009

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

3 голосов
/ 08 января 2009

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

Я бы настоятельно рекомендовал статическое утверждение (проверка во время компиляции), что sizeof (Example_class) == sizeof (example_struct), если вы делаете это. Смотрите BOOST_STATIC_ASSERT, или эквивалентную специфичную для компилятора или пользовательскую конструкцию. Это хорошая первая линия защиты, если кто-то (или что-то, например, изменение компилятора) модифицирует класс, чтобы сделать недействительным совпадение. Если вам нужна дополнительная проверка, вы также можете проверить во время выполнения, чтобы смещения элементов были одинаковыми, что (вместе с утверждением статического размера) гарантирует правильность.

1 голос
/ 22 декабря 2013

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

Различия связаны с наследованием классов и, особенно, с виртуальными функциями. Если класс содержит виртуальные функции, то он должен иметь указатель на дескриптор типа в начале своего макета. Кроме того, если класс B наследуется от класса A, то сначала идет макет класса A, а затем собственный макет класса B.

Итак, точный ответ на ваш вопрос о приведении экземпляра класса к экземпляру структуры: зависит от содержимого класса. Для конкретного класса, который имеет методы (конструктор и не виртуальный деструктор), компоновка, вероятно, будет одинаковой. Если деструктор будет объявлен виртуальным, компоновка определенно станет другой для структуры и класса.

Вот статья, в которой показано, что для перехода от структур C к классам C ++ не нужно много делать: Урок 1 - От структуры к классу

А вот статья, которая объясняет, как таблица виртуальных функций вводится в классы, которые имеют виртуальные функции: Урок 4 - Полиморфизм

0 голосов
/ 08 января 2009

Вы, вероятно, просто выводите класс из структуры, публично или приватно. Затем приведение будет правильно разрешено в коде C ++.

0 голосов
/ 08 января 2009

Почему бы явно не назначить членов класса структуре, когда вы хотите передать данные в C? Таким образом, вы знаете, что ваш код будет работать где угодно.

0 голосов
/ 08 января 2009

Классы и структуры в C ++ являются эквивалентными, за исключением того, что все члены структуры являются открытыми по умолчанию (члены класса по умолчанию являются закрытыми). Это гарантирует, что компиляция устаревшего кода C в компиляторе C ++ будет работать как положено.

Ничто не мешает вам использовать все необычные функции C ++ в структуре:

struct ReallyAClass
{
    ReallyAClass();
    virtual !ReallAClass();

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