Изменяет ли public/private/protected расположение структуры в памяти?

Редактировать: я только что придумал гораздо более простой способ задать этот вопрос:

Учитывая следующие две структуры:

class Thing {public: int a; public: int b; public: int c;}

class Thing {public: int a, private: int b; public: int c;}

Гарантируется ли, что члены a, b и c будут находиться в памяти в одном и том же порядке для обоих этих определений?


Старый вопрос

Допустим, у нас есть этот код C++ в fileA.cpp:

class Thing
{
public:
    int a;
    double num;

    Thing()
    {
        b = 10;
    }

    float getB()
    {
        return b;
    }

private:
    float b;
    Thing * other;
}

void doSomething(Thing thing);

int main()
{
    Thing thing;
    doSomething(thing);
    std::cout << thing.b;
}

И допустим, у нас есть этот код в fileB.cpp:

class Thing
{
public:
    int a;
    double num;

    Thing()
    {
        b = 10;
    }

    float getB()
    {
        return b;
    }

    float b;

private:
    Thing * other;
}

void doSomething(Thing thing)
{
    thing.b = 30;
}

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

Редактировать. Чтобы сделать это более очевидным, единственная разница между двумя определениями Thing заключается в том, что float b; является частным в fileA.cpp, но общедоступным в fileB.cpp.


person NetherGranite    schedule 10.10.2018    source источник
comment
Независимо от того, как они расположены, вы нарушаете правило одного определения. У вас может быть только одно определение объекта.   -  person NathanOliver    schedule 10.10.2018
comment
Это то, для чего предназначен friend, или, что еще лучше, правильный объектно-ориентированный дизайн, чтобы избежать этой проблемы.   -  person tadman    schedule 10.10.2018
comment
Да, он будет генерировать тот же код   -  person kerrytazi    schedule 10.10.2018


Ответы (1)


Стандарт не дает такой гарантии. У вас есть гарантии макета только для классов стандартного макета:

Класс стандартной компоновки — это класс, который:

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

(C++14, [класс] ¶7)

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

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

Порядок размещения нестатических элементов данных с различным контролем доступа не указан.

(C++14, [class.mem] ¶13)


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

person Matteo Italia    schedule 10.10.2018
comment
Я не понимаю обоснования этого. Чего можно было бы достичь с помощью этой гибкости? - person Martin; 22.04.2020
comment
@Martin: для меня это тоже загадка; мое единственное представление об этом заключалось в том, что, возможно, некоторые ранние реализации сохраняли элементы с различным контролем доступа в отдельных списках, а затем выводили их в фиксированном порядке (например, сначала все общедоступные, затем все защищенные, затем все частные), или что они даже были выводятся в базовой структуре C в отдельные подструктуры по какой-то причине, но все эти гипотезы кажутся надуманными. - person Matteo Italia; 22.04.2020
comment
Другая возможность, которая приходит на ум, заключается в том, что, возможно, они думали, что, учитывая, что со спецификаторами доступа класс перестает быть C-стилем и, таким образом, подчиняться более старым API, компиляторы могут использовать эту возможность для изменения порядка членов и уменьшения заполнения, но даже это не так. кажется правдоподобным. - person Matteo Italia; 22.04.2020
comment
Здесь может быть объяснение: stackoverflow.com/q/41407540/214671, что-то похожее на мою первую мысль (некоторые существующие реализация изменила макет в зависимости от спецификаторов доступа). - person Matteo Italia; 22.04.2020