С данным дизайном вы не можете ее решить. Проблема в том, что, хотя вы можете извлекать и переопределять методы, элементы данных не могут быть переопределены, члены, которые не переопределяются в производном классе, будут обращаться к полю точно так же, как они это делают, и в результате вы будете используя разные размеры в разных местах.
Время полиморфизма
Я не особо задумывался над дизайном, но первый простой подход во время выполнения - рефакторинг всего существующего кода, чтобы вместо прямого доступа к полям они делали это с помощью средств доступа ( setters и getters ), и это сопоставляет аргументы с типами хранения. Вы сможете переопределить эти средства доступа, и функции не будут зависеть от точного размера каждого битового поля. С другой стороны, наличие виртуальных методов доступа означает, что будет существовать экземпляр производительности, поэтому вы можете рассмотреть
Время компиляции (или статический) полиморфизм
Вы можете изменить класс таким образом, чтобы он представлял собой шаблон, принимающий в качестве аргумента тип объединения. Таким образом, вы можете создать экземпляр шаблона с другим объединением в то, что было бы в вашем текущем проекте производным классом. Добавление новых функций-членов (если вы хотите использовать функции-члены) не будет таким простым, и вам может понадобиться использовать CRTP или какой-то другой подход для создания base реализации, позволяя вам расширить его специализацией.
template <typename R>
class A
{
R xReg;
public:
unsigned int read_x1() const {
return xReg.x1;
}
// rest of implementation
};
union xReg1 {
unsigned int all;
struct {
unsigned int x3 : 9;
unsigned int x2 : 9;
unsigned int x1 : 14;
};
};
union xReg2 {
unsigned int all;
struct {
unsigned int x3 : 8;
unsigned int x2 : 9;
unsigned int x1 : 15;
};
};
int main() {
A< xReg1 > initial;
std::cout << initial.access_x1() << std::endl;
A< xReg2 > second;
std::cout << second.access_x1() << std::endl;
}