0

In the following code, I've got an interface called IDecoder which should be implemented by any decoder class (DecoderA and DecoderB here). IDecoder has a bitset<> in it, therefore I've made IDecoder a template class and the size of bitset is determined in the derived classes. I've also got a Container class which should hold a pointer to the IDecoder class, but since IDecoder is not a complete type, I've added a dummy DecoderBase class from which IDecoder inherits:

#include <iostream>
#include <bitset>

class DecoderBase
{
public:
    DecoderBase(){}
    virtual ~DecoderBase(){}
};

template<size_t nb>
class IDecoder : public DecoderBase
{
public:
    IDecoder(){}
    virtual ~IDecoder(){}
    virtual std::bitset<nb> GetDecodedFields() = 0;
};

const int DecoderAMaxFields = 100;
const int DecoderBMaxFields = 200;

class DecoderA : public IDecoder<DecoderAMaxFields>
{
public:
    DecoderA(){}
    ~DecoderA(){}
    std::bitset<DecoderAMaxFields> GetDecodedFields()
    {
        std::bitset<DecoderAMaxFields> bits;
        // assume we've decoded fileds number 1 and 10 here
        bits[1] = 1;
        bits[10] = 1;
        return bits;
    }
};

class DecoderB : public IDecoder<DecoderBMaxFields>
{
public:
    DecoderB(){}
    ~DecoderB(){}
    std::bitset<DecoderBMaxFields> GetDecodedFields()
    {
        std::bitset<DecoderBMaxFields> bits;
        // assume we've decoded fileds number 11, 29, 110 & 142 here
        bits[11] = 1;
        bits[29] = 1;
        bits[110] = 1;
        bits[142] = 1;
        return bits;
    }
};

class Container
{
public:
    Container(){}
    virtual ~Container(){}
    void SetDecoder(DecoderBase* decoder)
    {
        mDecoder = decoder;
    }
    DecoderBase* GetDecoder()
    {
        return mDecoder;
    }
private:
    DecoderBase* mDecoder;
};

int main()
{
    Container container;
    container.SetDecoder(new DecoderA());
    ((DecoderA*)container.GetDecoder())->GetDecodedFields();
    return 0;
}

As you can see, before calling GetDecodedFields() I have to cast it to one of the decoders, which is the exact reverse opposite of the purpose of polymorphism! How can I fix this code? I've also thought of using boost::dynamic_bitset but I'd prefer not to use it for it's slower than normal bitset.

B Faley
  • 17,120
  • 43
  • 133
  • 223
  • What (functionally) are you trying to achieve (what is the `bitset` used for)? – bobah Aug 31 '15 at 09:23
  • 1
    What kind of `Decoder` the `Container` uses is runtime information, while the size of the `bitset` must be declared at compile time. These two concept won't work together. You should think about using `vector`. – Simon Kraemer Aug 31 '15 at 09:27
  • BTW: The types of `std::bitset<100>` and `std::bitset<200>` are different. There is no type `std::bitset` that can be used as a base class. That's not how templates work. So `DecoderBase` can't know which of the types you want to return. – Simon Kraemer Aug 31 '15 at 09:35
  • 1
    `dynamic_bitset` is inevitably slightly slower - but does it actually matter for your purpose? It certainly looks like the simplest solution to your problem. – Alan Stokes Aug 31 '15 at 09:54
  • @bobah I need this bitset for bitwise operations so that I can quickly know which fields have been decoded. – B Faley Aug 31 '15 at 10:17
  • @SimonKraemer I'd prefer not to use `vector` because bitwise operations are not easy on that. – B Faley Aug 31 '15 at 10:18
  • Then I think you should go with `boost::dynamic_bitset`. The only other ways I could think of would be to build you on `dynamic_bitset` (e.g. using a `vector>`) or use a `std::bitset` that is large enough to manage all use cases and return the used-size in addition to it. The first will require a lot of work to be done by yourself to provide an usable interface, the second might not always work the way you want it to... – Simon Kraemer Aug 31 '15 at 11:59
  • @SimonKraemer You are right, I think `boost::dynamic_bitset` would be my best bet at the moment. – B Faley Aug 31 '15 at 12:03

2 Answers2

0

EDIT: This answer is additional to the comments made under the question.

  • What kind of Decoder the Container uses is runtime information, while the size of the bitset must be declared at compile time. These two concept won't work together. You should think about using vector.
  • BTW: The types of std::bitset<100> and std::bitset<200> are different. There is no type std::bitset that can be used as a base class. That's not how templates work. So DecoderBase can't know which of the types you want to return.

Example on how to used std::vector<bool> instead of fixed-size std::bitset<N>in this case:

#include <iostream>
#include <bitset>
#include <vector>

class DecoderBase
{
public:
    DecoderBase() {}
    virtual ~DecoderBase() {}
    virtual std::vector<bool> GetDecodedFields() = 0;
};

class DecoderA : public DecoderBase
{
public:
    DecoderA() {}
    ~DecoderA() {}
    std::vector<bool> GetDecodedFields()
    {
        // assume we've decoded fileds number 1 and 10 here
        std::vector<bool> bits(100, false);
        bits[1] = true;
        bits[10] = true;
        return bits;
    }
};

class DecoderB : public DecoderBase
{
public:
    DecoderB() {}
    ~DecoderB() {}
    std::vector<bool> GetDecodedFields()
    {
        // assume we've decoded fileds number 11, 29, 110 & 142 here
        std::vector<bool> bits(200, false);
        bits[11] = 1;
        bits[29] = 1;
        bits[110] = 1;
        bits[142] = 1;
        return bits;
    }
};

class Container
{
public:
    Container() {}
    virtual ~Container() {}
    void SetDecoder(DecoderBase* decoder)
    {
        mDecoder = decoder;
    }
    DecoderBase* GetDecoder()
    {
        return mDecoder;
    }
private:
    DecoderBase* mDecoder;
};

int main()
{
    Container container;
    container.SetDecoder(new DecoderA());
    container.GetDecoder()->GetDecodedFields();
    std::cout << container.GetDecoder()->GetDecodedFields().size() << std::endl;
    return 0;
}
Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49
0

The problem here is not polymorphism.

You're using a heterogenous container.

There is no construct in C++ to access the elements of such a container without using casts.

The clean way would be to dynamic_cast<> on the container elements to cast the elements to their respective type.

A.Franzen
  • 725
  • 4
  • 10