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

Viewed 90

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
    // Is this legal?
    ModuleTester* testerMask = static_cast<ModuleTester*>(&module); 
    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.

EDIT: I found a similar method that doesn't use explicit pointer casting (https://stackoverflow.com/a/1725107/649700). It works, is arguably less readable and probably does not change the 'legality' status.

(module.*&ModuleTester::protectedVirtualFunction)(4.4f);

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++?

1 Answers

This would be Undefined Behavior since &module does not point at subobject of object ModuleTester:

8.5.1.9 Static cast [expr.static.cast]
11 A prvalue of type “pointer to cv1 B ”, where B is a class type, can be converted to a prvalue of type “pointer to cv2 D ”, where D is a class derived (Clause 13) from B , if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If B is a virtual base class of D or a base class of a virtual base class of D , or if no valid standard conversion from “pointer to D ” to “pointer to B ” exists (7.11), the program is ill-formed. The null pointer value (7.11) is converted to the null pointer value of the destination type. If the prvalue of type “pointer to cv1 B ” points to a B that is actually a subobject of an object of type D , the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.

#define private public is also not a good idea:

2 A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in 10.6.

Related