Template class extending from non-template base class and overriding function parameters

Viewed 362

I am trying to create a non-template base class for the PacketDecoder so I can store Base* in a std::map. The decode function is being overridden properly. The encode function is giving me this error "'encode' is not virtual and cannot be declared pure". I might be thinking about this problem wrong coming from a Java background. Is there a more idiomatic c++ approach to this problem?

class Base {
public:
    virtual Packet* decode(folly::io::Cursor& cursor) = 0;
    virtual void encode(Packet* packet) = 0;
};

template<typename T, typename std::enable_if<std::is_base_of<Packet, T>::value>::type* = nullptr>
class PacketDecoder : public Base {
public:
    virtual T* decode(folly::io::Cursor& cursor) = 0;
    virtual void encode(T *packet) = 0;
};

Example usage:

class TestDecoder : public PacketDecoder<ProxyJoinPacket> {
public:
    ProxyJoinPacket *decode(folly::io::Cursor &cursor) override {
        uint32_t stringLength;
        if (!cursor.tryReadBE<uint32_t>(stringLength)) {
            throw std::runtime_error("Failed to read string length");
        }

        if (cursor.length() < stringLength) {
            throw std::runtime_error("Too few bytes for string");
        }

        auto uuid = cursor.readFixedString(stringLength);
        return new ProxyJoinPacket(uuid);
    }

    void encode(ProxyJoinPacket *packet) override {

    }


};

std::vector<Base*> decoders;
void a() {
    decoders.insert(new TestDecoder()); // error "Allocating an object of abstract class type 'TestDecoder'"
}
1 Answers

The issue is that your original class has this virtual function:

virtual void encode(Packet* packet) = 0;

Then your inherited class has this:

virtual void encode(T *packet) = 0;

That's two different virtual functions.

So when you do:

void encode(ProxyJoinPacket *packet) override {

You only override the method int he inherited class, not in Base, which is still missing.

So change your inherited class to use Packet

virtual void encode(Packet* packet) = 0;

You can also change your inherited class and add something like:

void encode(Packet* packet) final {
    encode(dynamic_cast<T*> packet);
}

Don't forget the virtual destructors as well...

Related