изменить размер бит упакованной структуры в производном классе - PullRequest
1 голос
/ 01 июля 2011

Существующий код:

typedef unsigned int uint;
Class A
{
union xReg
    {
        uint allX;
        struct
        {
            uint x3      : 9;
            uint x2      : 9;
            uint x1      : 14;
        }__attribute__((__packed__)) __attribute__((aligned(4)));
    };
};

Мое требование: Теперь мне нужно извлечь класс из A, а в производном классе размеры битов x1, x2 и x3 должны измениться.

Как мне это сделать?Спасибо за вашу помощь!

РЕДАКТИРОВАТЬ

У меня есть класс (скажем, A) с ок.7-8 союзов (каждый из которых представляет регистр HW) и около 20 (прибл.) Функций.Большинство из этих функций создают экземпляры этих объединений и используют биты (x1, x2, x3 и т. Д. В моем примере).

Теперь мое требование состоит в том, чтобы добавить код для нового оборудования с 95% функциональноститак же.Изменения включают в себя изменение размеров битов регистра и некоторые функциональные изменения.Итак, среди 20 функций, по крайней мере, 5 функций, которые мне нужно изменить, чтобы изменить реализацию.Это причина для меня, чтобы выбрать наследование и переопределить эти функции.

Остальные 15 функций, изменяются только изменения размера битов.Поэтому я не хочу переопределять эти функции, но использую базовый класс.Но размеры битов регистров (объединений) должны измениться.Как мне это сделать?

Ответы [ 3 ]

3 голосов
/ 01 июля 2011

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

Однако вы можете попробовать параметризовать ваш класс длинами полей bit_field.

template <size_t N1, size_t N2, size_t N3 = 32 - N1 - N2>
struct myStruct
{
    uint bitField1 : N1;
    uint bitField2 : N2;
    uint bitField3 : N3;
};

Теперь вы можете создать экземпляр структуры с любым N1, N2, N3, например:

myStruct<9, 9> s;
1 голос
/ 02 июля 2011

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

Время полиморфизма

Я не особо задумывался над дизайном, но первый простой подход во время выполнения - рефакторинг всего существующего кода, чтобы вместо прямого доступа к полям они делали это с помощью средств доступа ( 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;
}
0 голосов
/ 02 июля 2011

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

Вы, возможно, вообще не хотите использовать функции-члены.

template<typename reg>
union hardware_register {
    unsigned all;
    struct {
        unsigned i : reg::i;
        unsigned j : reg::j;
        unsigned k : reg::k;
    };
};

template<typename hardware>
void print_fields(const hardware& hw) {
   cout << hw.i << " " << hw.j << " " << hw.k << endl;
}

//this method needs special handling depending on what type of hardware you're on
template<typename hardware>
void print_largest_field(const hardware& hw);

struct register_a {
    static const unsigned i = 9;
    static const unsigned j = 4;
    static const unsigned k = 15;
};

struct register_b { 
    static const unsigned i = 4;
    static const unsigned j = 15;
    static const unsigned k = 9;
};

template<>
void print_largest_field<register_a>(const register_a& a) {
    cout << a.k << endl;
}

template<>
void print_largest_field<register_b>(const register_b& b) {
    cout << b.j << endl;
}

int main() {
    hardware_register<register_a> a;
    hardware_register<register_b> b;
    print_fields(a);
    print_fields(b);
    print_largest_field(a);
    print_largest_field(b);
}

Кроме того, вы можете объединить все общие функции в шаблонный базовый класс. Вы наследуете от этого базового класса и реализуете любое специальное поведение, которое вам нужно.

template<typename HW> 
struct base {
    void print_fields {
        cout << hw.i << hw.j << hw.k << endl;
    };
private:
    HW hw;
};

struct hw_a : base<register_a> {
    void print_largest_field {
        cout << hw.k << end;
    }
};

struct hw_b : base<register_b> {
    void print_largest_field {
        cout << hw.j << end;
    }
};

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

...