vendredi 3 avril 2020

Cast to child object for testing - is this code standard-conforming?

TL;DR

Is this casting/function call legal, standard-conforming C++11/14 code?
If not, would it be if there were no virtual functions (if std::is_standard_layout<Module> became true)?
(NB: It works on every compiler I've tested it so far...)

class Module
{
protected:
    virtual float protectedVirtualFunction(float f) { return f*f*f; }
    float protectedFunction(float f) { return f*f; }
};

class ModuleTester : public Module // consists of ONLY aliases
{
public:
    using Module::protectedFunction;
    using Module::protectedVirtualFunction;
};

int main()
{
    Module module;  //assume this is a pre-existing instance
    ModuleTester* testerMask = static_cast<ModuleTester*>(&module); // Is this legal?
    testerMask->protectedFunction(4.4f);
    testerMask->protectedVirtualFunction(4.4f);
}

Additional Information

Usually, I aim to test a classes public API only when writing UnitTests. In some cases - like when you're dealing with legacy code you can't change - it's just more practical to access private members.

So, assuming we cannot change the design (DI, decoupling...), I see the following solutions:

  1. Make private members public (compromising all encapsulation)
  2. The ol' trick: #define private public in test context
  3. The "Tester" pattern (as used in example code)

The standard way of using this "Tester" pattern would be like, and that should be legal:

    ModuleTester tester;
    tester.protectedFunction(4.4f);
    tester.protectedVirtualFunction(4.4f);

However, sometimes I have an existing instance and it would be great if I could just apply this "tester mask" on top of it to gain access.

My guess is that as soon as I virtual functions and stop being "standard layout", there could be "undefined behaviour" strictly speaking. However, if I'm only defining aliases in the derived class, I don't see how this could go wrong as long as I use the same compiler for Module and ModuleTester.

Other SO questions that make some good points: reinterpret_cast from object to first member, How do I unit test a protected method in C++?

Aucun commentaire:

Enregistrer un commentaire