parsley72
parsley72

Reputation: 9037

Subclassing a virtual function with a subclassed type

I turned on some compiler warnings (C4263 and C4264) and found this bug:

class tCommand
{
    ...
};

class tTestModule
{
public:
    virtual bool HandleCommand(tCommand&) { return false; }
}

class tCommandADCReadings : public tCommand
{
    ...
};

class tADCReadings : public tTestModule
{
public:
    tADCReadings();

    bool HandleCommand(tCommandADCReadings&);
}

bool tADCReadings::HandleCommand(tCommandADCReadings& cmd)
{
    ...
}

This shows a warning because the implementation of tADCReadings::HandleCommand() doesn't match tTestModule::HandleCommand(). So I fixed it like this:

class tADCReadings : public tTestModule
{
public:
    tADCReadings();

    bool HandleCommand(tCommand&) override;
}

bool tADCReadings::HandleCommand(tCommand& cmd)
{
    tCommandADCReadings* pCmdADCReadings = dynamic_cast<tCommandADCReadings*>(&cmd);
}

But another team member says we should keep the type checking that using tCommandADCReadings in tADCReadings::HandleCommand() gives us, so just remove tTestModule::HandleCommand(). But this function is used in ~10 other subclasses as well so it seems a shame. Is there another way to keep the virtual and ensure compile-time type correctness?

Upvotes: 0

Views: 114

Answers (1)

Bowie Owens
Bowie Owens

Reputation: 2976

"Is there another way to keep the virtual and ensure compile-time type correctness?" The answer depends on how you utilise tCommand objects in the rest of your code. Lets say you have code similar to:

typedef std::vector<std::shared_ptr<tTestModule>> module_list;

bool handle(tCommand& c, module_list const& m)
{
    bool fin = false;
    for (auto i = m.begin(), e = m.end(); i != e && !fin; ++i)
        fin = (*i)->HandleCommand(c);

    return fin;
}

In this case you have a tCommand object of unknown final type that is passed to a variety of tTestModule objects also of unknown final type. In this case the answer is no. You cannot have runtime dispatch and compile time type safety with two unknown types.

To get compile time safety you need to know at least one of the types involved as in the following:

template <class C>
bool handle(C& c, module_list const& m)
{
    bool fin = false;
    for (auto i = m.begin(), e = m.end(); i != e && !fin; ++i)
        fin = (*i)->HandleCommand(c);

    return fin;
}

But for type safety you actually need to overload HandleCommand() in tTestModule for every type derived from tCommand. If you could also know the types of the modules in m at compile time (ie using a std::tuple of modules by value instead of a vector of modules by reference), you would have type safety without the overloading headache.

Upvotes: 1

Related Questions