1

The existing code:

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)));
    };
};

My requirement: Now, I need to derive a class from A, and and in the derived class, the bit sizes of x1, x2 and x3 has to change.

How do i do this ? Thanks for your help !

EDIT

I have a class (lets say A) with approx. 7-8 unions (each representing HW register), and around 20 (approx.) functions. Most of these functions create instances of these unions, and use the bits (x1, x2, x3 etc in my example).

Now, my requirement is to add code for a new hardware which has 95% of functionality same. The changes include the change in register bit sizes, and some functionality change. So, among 20 functions, atleast 5 functions I need to change to change the implementation. This is the reason for me to select inheritance and override these functions.

The rest 15 functions, only change is the bit size changes. So, I dont want to override these functions, but use the base class ones. But, the bit sizes of the registers (unions) should change. How do I do that?

timrau
  • 22,578
  • 4
  • 51
  • 64
singleX
  • 375
  • 4
  • 13
  • You do realize that you are defining a nested type and not an attribute, right? Do you want to define a different nested type in the derived class? Or is it an error and what you want is an attribute and different interpretations of it? – David Rodríguez - dribeas Jul 01 '11 at 17:36
  • the latter. I dont want to override the methods of base class which are using this attribute. – singleX Jul 01 '11 at 18:09
  • Why inheritance? You should explain your actual problem to solve, as there might be different approaches. The option of inheritance does not make sense here, it would mean that depending on at what level you hold the reference/pointer, the semantics of access to the bitfield would differ. – David Rodríguez - dribeas Jul 01 '11 at 19:42
  • I have a class (lets say A) with approx. 7-8 unions (each representing HW register), and around 20 (approx.) functions. Most of these functions create instances of these unions, and use the bits (x1, x2, x3 etc in my example). – singleX Jul 01 '11 at 19:52
  • Now, my requirement is to add code for a new hardware which has 95% of functionality same. The changes include the change in register bit sizes, and some functionality change. So, among 20 functions, atleast 5 functions I need to change to change the implementation. This is the reason for me to select inheritance and override these functions. – singleX Jul 01 '11 at 19:53
  • The rest 15 functions, only change is the bit size changes. So, I dont want to override these functions, but use the base class ones. But, the bit sizes of the registers (unions) should change. How do I do that ? – singleX Jul 01 '11 at 19:53
  • @David, I split the response due to limitation of characters – singleX Jul 01 '11 at 19:53

3 Answers3

3

You cannot change a bit-field length in a derived class in C++.

What you could try, however, is parametrize your class with the bit_field lengths.

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

Now you can instantiate the struct with any N1, N2, N3 you wish, for example:

myStruct<9, 9> s;
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • A clear nomination for the Best Abuse of Templates Award! :-) +1 – Bo Persson Jul 01 '11 at 17:59
  • Thanks for your response. It didnt go well with the unions. In my example given, I added template for the struct, and after that I am not able to create an instance of the union like xReg abc; Compilation fails. – singleX Jul 01 '11 at 19:30
1

With the given design you cannot solve it. The problem is that while you can derive and override methods, data members cannot be overridden, the members that are not overridden in the derived class would access the field in exactly the same way that they are doing, and the result is that you would be using different sizes in different places.

Runtime polymorphism

I haven't think much on the design, but the first simple runtime approach would be refactoring all the existing code so that instead of accessing the fields directly they do so by means of accessors (setters and getters), and that map the arguments to the storage types. You would be able to override those accessors and the functions would not depend on the exact size of each bitfield. On the negative side, having the accessors virtual means that there will be a performance instance, so you might consider

Compile time (or static) polymorphism

You can refactor the class so that it is a template that takes as argument the type of the union. That way, you can instantiate the template with a different union in what would be in your current design an derived class. Addition of new member functions (if you want to use member functions) would not be so simple, and you might end up having to use CRTP or some other approach to create the base of the implementation while allowing you to extend it with specialization.

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;
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Thanks David ! I need to inherit for sure to override certain functions. So, how does this template class and inheritance work ? Do I need to make the derived class also template ? – singleX Jul 03 '11 at 18:38
  • For starters, I am not sure that OO is the best approach to your particular problem. There are other ways of providing genericity, including templates and specialization, where some functions might be templated to perform exactly the same with all parameter types, while others can be overloaded to provide different implementations for different types. Inheritance is not to reuse old code in your new type, but to use your new type in existing code. – David Rodríguez - dribeas Jul 03 '11 at 23:35
  • Now, if you want to pursue that path, to split the implementations (ie, the equivalent of override) you would specialize the class. To maintain a common set of functions, you would have to move them to a common class that is used from multiple specializations... but that will not be simple. You would have to weight the different tradeoffs considering your complete problem in the domain, and guessing which of the options will get closer to your intended goal. There are other alternatives also, like injecting the register type dependency to the class, and then using pure OO – David Rodríguez - dribeas Jul 03 '11 at 23:40
  • (that would mean defining a `register_type` type that offers virtual methods to access each one of the registers, and using that type in your original object, but being able to replace the type with a derived type that overrides the behavior. That would make all of the old code able to operate on the new types of registers, and you could override the class that operates on the registers adding new operations (and overriding old ones). Without knowing the contraints, I cannot say how much performance you will loose in doing so. The problem is not *well defined* to make even an informed guess – David Rodríguez - dribeas Jul 03 '11 at 23:45
  • Thanks David for the detailed reply – singleX Jul 07 '11 at 19:05
0

Given your additional problem statement, a variant on what Armen suggested might be applicable. It sounds as though you do not need actual inheritance here, just some way to reuse some of the common code.

You might not want member functions at all, for instance.

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);
}

Alternatively, you can wrap up all the common functionality into a templated base class. You derive from that base class, and implement whatever special behavior you need.

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;
    }
};

You can provide multiple template parameters for your different types of registers, or expand on the underlying trait structure such that it defines more than one register at a time.

Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38