Доступ одного класса к protected полям другого класса с общим предком

Я делаю некую имитацию UI. Проблема в том, что при добавлении элемента в layout, он подгоняет позицию элемента под позицию других элементов и следовательно мне нужен доступ к этой переменной(_position). Однако компилятор не разрешает это сделать. Так как все элементы имеют одинакового предка, то по идее должен быть способ как-то обмануть компилятор. Изменять область видимости на public не очень хочется, так как нарушается инкапсуляция.

class UIObject{
protected:
    Rect _position;
...
}

class Text : public UIObject
{
...
}

class Layout : public UIObject
{
...
public:
   void add_object(UIObject* object){
       добавление в коллекцию
       ...
       изменение _position у object
       ...
   }
}

Ответы (3 шт):

Автор решения: AR Hovsepyan

В данном случаи объект Layout не является потомком объекта object, поэтому его функция_член не может пользоваться защищенным членом object. Но его функция_член может пользоваться защищенным и закрытым членом своего класса, поэтому, если приводить указатель к указателю на Layout, то можно получать доступ:

void add_object(UIObject* object) {
   static_cast<Layout*>(object)->_position = /*...*/;
}
→ Ссылка
Автор решения: HolyBlackCat

Обмануть компилятор можно через указатель-на-член. Но лучше найти какое-то нормальное решение, без подобных выкрутасов.

#include <iostream>

struct A
{
  protected:
    int x = 42;
};

struct B : A
{
    void foo(A *a)
    {
        // Не работает:
        // std::cout << a->x << '\n';

        // Вместо `auto` можно использовать `int A::*`.
        auto member = &B::x;
        std::cout << a->*member << '\n';
    }
};
→ Ссылка
Автор решения: Кирилл Чуркин

Почитав немного сайтов на данную тематику, я понял, что такой вопрос встречается довольно часто. Поэтому я решил немного резюмировать всю информацию. Доступ к protected членам запрещён документацией. Но это можно обойти, используя "pointers to members". Большое спасибо HolyBlackCat за оказанную помощь. Ниже я оставлю свой код(здесь так же есть использование и виртуальных функций, получилось добраться только так (компилятор msvc)).

class UIObject {
protected:
    Rectangle _position;
protected:
    virtual void update_position() {}
}

class Layout :
    public UIObject
{
protected:
    std::vector<std::unique_ptr<UIObject>> _objects;
}

class HorizontalLayout :
    public Layout
{
private:
    virtual void update_position() override {
        bool first_object_flag = true;
        decltype(auto) object_position = &HorizontalLayout::_position;
        _position.width = 0;
        for (auto&& object : _objects) {
            if (first_object_flag) {
                (*object.*object_position).x = _position.x;
                _position.width += (*object.*object_position).width;
                first_object_flag = false;
            }
            else {
                (*object.*object_position).x = _position.x + _position.width + 1;
                _position.width += ((*object.*object_position).width + 1);
            }
            (*object.*object_position).y = (_position.y * 2 + _position.height - 1) / 2 - object->height() / 2;
            decltype(auto) object_update_positiion = &HorizontalLayout::UIObject::update_position;
            ((*object).*object_update_positiion)();

        }
public:
    template<class _UIObject, class... Args>
    _UIObject& add_object(Args&&... args) {
        _objects.emplace_back(std::make_unique<_UIObject>(std::forward<Args>(args)...));
        decltype(auto) object = *_objects.back();
        decltype(auto) object_position = &HorizontalLayout::_position;
        if (_objects.size() == 1) {
            (object.*object_position).x = _position.x;
            _position.width += (object.*object_position).width;
        }
        else {
            (object.*object_position).x = _position.x + _position.width + 1;
            _position.width += ((object.*object_position).width + 1);
        }
        if(object.height() > _position.height){
            _position.height = object.height();
            this->update_position();
        }
        (object.*object_position).y = (_position.y*2 + _position.height - 1) / 2 - object.height() / 2;
        return static_cast<_UIObject&>(object);
    }
};
→ Ссылка