Make interchangeable class types via pointer casting only, without having to allocate any new objects?

前端 未结 4 1145
半阙折子戏
半阙折子戏 2020-12-17 04:24

UPDATE: I do appreciate \"don\'t want that, want this instead\" suggestions. They are useful, especially when provided in context of the motivating scenari

4条回答
  •  心在旅途
    2020-12-17 04:58

    If I understand you correctly, you have:

    • A NodeBase class that is stateful, and the true workhorse of the system;
    • a set of stateless Accessor types that provide an interface to NodeBase; and
    • a Node class which wraps an accessor, presumably providing convenience functions.

    I assume the last bit because if you don't have a wrapper type that does convenience stuff, then there's no reason not to make the Accessor types your top-level, like you suggested: pass AccessorFoo and AccessorBar around by value. The fact that they aren't the same object is entirely moot; if you think of them like the pointers that they are, then you'll note that &foo != &bar is no more interesting than having NodeBase* p1 = new NodeBase; NodeBase* p2 = p1; and noting that, of course, &p1 != &p2.

    If you really do need a wrapper Node and want to make it standard-layout, then I would suggest that you use the statelessness of your Accessor types to your advantage. If they are simply a stateless container of functionality (which they must be; why else would you be able to freely cast them?), then you can do something like this:

    struct AccessorFoo {
        int getValue(NodeBase* n) { return n->getValueFoo(); }
    };
    
    struct AccessorBar {
        int getValue(NodeBase* n) { return n->getValueBar(); }
    };
    
    template 
    class Node {
        NodeBase* m_node;
    
    public:
        int getValue() {
            AccessorT accessor;
            return accessor.getValue(m_node);
        }
    };
    

    In this case, you could add a templated conversion operator:

    template 
    operator Node() {
        return Node(m_node);
    }
    

    And now you've got direct value conversion between any Node type you like.

    If you take it just a bit further, you'll make all the methods of the Accessor types static, and arrive at the traits pattern.


    The section of the C++ standard that you quoted, incidentally, concerns the behavior of reinterpret_cast(p) in the case that both the source type and the final type are pointers to standard-layout objects, in which case the standard guarantees that you get the same pointer you'd get from casting to a void* and then to the final type. You still don't get to use the object as any type other than the type it was created as without invoking undefined behavior.

提交回复
热议问题