2

Below code came from a post about C++ interview questions here. I've never known this technique :) (though it's claimed a good one :)). My questions are: In which situation do we need to use it? Do you often see it in your real production/legacy code?

Question:

Implement a method to get topSecretValue for any given Something* object. The method should be cross-platform compatible and not depend on sizeof (int, bool, string).

class Something {
    Something() {
        topSecretValue = 42;
    }
    bool somePublicBool;
    int somePublicInt;
    std::string somePublicString;
private:
    int topSecretValue;
};

Answer:

Create another class which has all the members of Something in the same order, but has additional public method which returns the value. Your replica Something class should look like:

class SomethingReplica {
public:
    int getTopSecretValue() { return topSecretValue; } // <-- new member function
    bool somePublicBool;
    int somePublicInt;
    std::string somePublicString;
private:
    int topSecretValue;
};

int main(int argc, const char * argv[]) {
    Something a;
    SomethingReplica* b = reinterpret_cast<SomethingReplica*>(&a);
    std::cout << b->getTopSecretValue();
}

It’s important to avoid code like this in a final product, but it’s nevertheless a good technique when dealing with legacy code, as it can be used to extract intermediate calculation values from a library class. (Note: If it turns out that the alignment of the external library is mismatched to your code, you can resolve this using #pragma pack.)

rustyx
  • 80,671
  • 25
  • 200
  • 267
Tien Do
  • 10,319
  • 6
  • 41
  • 42
  • You might want to study the *visitor* and *observer* patterns. – Bathsheba Feb 27 '19 at 14:00
  • 2
    Pedantically, it is UB as aliasing rule is broken. but might work in practice. – Jarod42 Feb 27 '19 at 14:16
  • 1
    As hack, adding friend or public method would do the job too. (as it should not go in production, it is only for temporary testing). – Jarod42 Feb 27 '19 at 14:18
  • @eerorika where is to strict aliasing question? (it seems rustyx removed his comment). – Tien Do Feb 27 '19 at 14:25
  • 2
    See [What is the strict aliasing rule?](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) and [\[basic.lval\]/10](https://timsong-cpp.github.io/cppwp/n3337/basic.lval#10). @eerorika btw not sure about the standard-layout exception. – rustyx Feb 27 '19 at 14:28
  • 3
    This code is UB. It violates the [One Definition Rule](https://en.cppreference.com/w/cpp/language/definition). There are safer methods to "hack" a private member. This approach should never be used at any level of code. – BiagioF Feb 27 '19 at 14:34
  • 2
    Goes to show that not all "C++ interview questions" are created equal. On second thought, they're all abysmal. – Passer By Feb 27 '19 at 14:40
  • @rustyx you appear to be right. I must have mixed strict aliasing with some other case. I think layout-compatibility would have made union punning OK (if the classes were layout-compatible). – eerorika Feb 27 '19 at 14:43
  • 1
    @PasserBy disagree. My C++ interview questions are superb! :) – SergeyA Feb 27 '19 at 16:01
  • 1
    I always solve this problem with a very simple code: `#define class struct #define private public` ;) – SergeyA Feb 27 '19 at 16:02
  • @SergeyA: But then, you might break layout (as you no longer mix private/public section, disallowing some potential reorganization), name mangling might also be impacted. (you also break ODR). – Jarod42 Feb 28 '19 at 13:18
  • @Jarod42 Yes, this is very undefined behaviorish. I only used it once in production code, because of some too-stupid-to-explain policies, but it got the job done. – SergeyA Feb 28 '19 at 14:18

1 Answers1

7

You can do this without reinterpret_cast. There is a trick using templates and friends that is outlined in the following blog post that demonstrates the technique:

Access to private members. That's easy!

This is certainly safer than the interviewer's approach, since it eliminates human error in re-creating the class definition. Is this approach good at all, though? The given question has some incredibly artificial constraints that would rarely apply to a 'real' project. If it's a C++ project and you have access to the header file, why not just add a getter? If it's not a C++ project, why are you so constrained in your definition of the interop class?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Chuu
  • 4,301
  • 2
  • 28
  • 54
  • 5
    There also is libraries that exist just for that. I'm particularly impressed with their macro less solution: https://github.com/hliberacki/cpp-member-accessor – Guillaume Racicot Feb 27 '19 at 14:11
  • Why not modify header file? The interviewer might say he wants to test your knowledge about layout compatibility :) – Tien Do Feb 28 '19 at 15:05
  • Offtopic: @GuillaumeRacicot good to know someone use it ;) or maybe it's not that good :D considering character of that lib. – Hubert Liberacki Dec 16 '21 at 11:21