Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8221725
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 7, 20262026-06-07T14:01:52+00:00 2026-06-07T14:01:52+00:00

( Note: I’m looking for really any suggestions on the right search terms to

  • 0

(Note: I’m looking for really any suggestions on the right search terms to read up on this category of issue. “Object-relational-mapping” occurred to me as a place where I could find some good prior art…but I haven’t seen anything quite fitting this scenario just yet.)

I have a very generic class Node, which for the moment you can think of as being a bit like an element in a DOM tree. This is not precisely what’s going on–they’re graph database objects in a memory mapped file. But the analogy is fairly close for all practical purposes, so I’ll stick to DOM terms for simplicity.

The “tag” embedded in the node implies a certain set of operations you should (ideally) be able to do with it. Right now I’m using derived classes to do this. So for instance, if you were trying to represent something like an HTML list:

<ul>
   <li>Coffee</li>
   <li>Tea</li>
   <li>Milk</li>
</ul>

The underlying tree would be seven nodes:

+--UL                       // Node #1
   +--LI                    // Node #2
      +--String(Coffee)     // Node #3 (literal text)
   +--LI                    // Node #4
      +--String(Tea)        // Node #5 (literal text)
   +--LI                    // Node #6
      +--String(Milk)       // Node #7 (literal text)

Since getString() is already a primitive method on Nodes themselves, I’d probably only make class UnorderedListNode : public Node, class ListItemNode : public Node.

Continuing this hypothetical, let’s imagine I wanted to help the programmer use less general functions when they know more about the Node “type”/tag they have in their hands. Perhaps I want to assist them with structural idioms on the tree, like adding a string item to an unordered list, or extracting things as a string. (This is just an analogy so don’t take the routines too seriously.)

class UnorderedListNode : public Node {
private:
    // Any data members someone put here would be a mistake!

public:
    static boost::optional<UnorderedListNode&> maybeCastFromNode(Node& node) {
        if (node.tagString() == "ul") {
            return reinterpret_cast<UnorderedListNode&>(node);
        }
        return boost::none;
    }

    // a const helper method
    vector<string> getListAsStrings() const {
        vector<string> result;
        for (Node const* childNode : children()) {
            result.push_back(childNode->children()[0]->getText());
        }
        return result;
    }

    // helper method requiring mutable object
    void addStringToList(std::string listItemString) {
        unique_ptr<Node> liNode (new Node (Tag ("LI"));
        unique_ptr<Node> textNode (new Node (listItemString));
        liNode->addChild(std::move(textNode));
        addChild(std::move(liNode));
    }
};

Adding data members to these new derived classes is a bad idea. The only way to really persist any information is to use the foundational routines of Node (for instance, the addChild call above, or getText) to interact with the tree. Thus the real inheritance model–to the extent one exists–is outside of the C++ type system. What makes a <UL> node “maybeCast” into an UnorderedListNode has nothing to do with vtables/etc.

C++ inheritance looks right sometimes, but feels wrong usually. I feel like instead of inheritance I should have classes that exist independently of Node, and just collaborate with it somehow as “accessor helpers”…but I don’t have a good grasp of what that would be like.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-07T14:01:53+00:00Added an answer on June 7, 2026 at 2:01 pm

    “C++ inheritance looks right sometimes, but feels wrong usually.”

    Indeed, and this statement is worrisome:

    What makes a node “maybeCast” into an UnorderedListNode has nothing to do with vtables/etc.

    As is this code:

    static boost::optional<UnorderedListNode&> maybeCastFromNode(Node& node) {
        if (tagString() == "ul") {
            return reinterpret_cast<UnorderedListNode&>(node);
        }
        return boost::none;
    }
    

    (1) type-punning

    If the Node& being passed in was allocated through a mechanism that did not legally and properly construct an UnorderedListNode on the inheritance path, this is what is called type punning. It’s almost always a bad idea. Even if the memory layout on most compilers appears to work when there are no virtual functions and derived classes add no data members, they are free to break it in most all circumstances.

    (2) strict-alias

    Next there is the compiler’s assumption that pointers to objects of fundamentally different types do not “alias” each other. This is the strict aliasing requirement. Although it can be disabled via non-standard extensions, that should only be applied in legacy situations…it hinders optimization.

    It’s not completely clear–from an academic standpoint–whether these two hindrances have workarounds permitted by the spec under special circumstances. Here’s a question which investigates that, and is still an open discussion at time of writing:

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

    But to quote @MatthieuM.: “The closer you get to the edges of the specifications, the more likely you are to hit a compiler bug. So, as engineer, I advise to be pragmatic and avoid playing mind games with your compiler; whether you are right or wrong is irrelevant: when you get a crash in production code, you lose, not the compiler writers.”

    This is probably more the right track:

    I feel like instead of inheritance I should have classes that exist independently of Node, and just collaborate with it somehow as “accessor helpers”…but I don’t have a good grasp of what that would be like.

    Using Design Pattern terms, this matches something like a Proxy. You would have a lightweight object that stores the pointer and is then passed around by value. In practice, it can be tricky to handle issues like what to do about the const-ness of the incoming pointers being wrapped!

    Here’s a sample of how it might be done relatively simply for this case. First, a definition for the Accessor base class:

    template<class AccessorType> class Wrapper;
    
    class Accessor {
    private:
        mutable Node * nodePtrDoNotUseDirectly;
    template<class AccessorType> friend class Wrapper;
        void setNodePtr(Node * newNodePtr) {
            nodePtrDoNotUseDirectly = newNodePtr;
        }
        void setNodePtr(Node const * newNodePtr) const {
            nodePtrDoNotUseDirectly = const_cast<Node *>(newNodePtr);
        }
        Node & getNode() { return *nodePtrDoNotUseDirectly; }
        Node const & getNode() const { return *nodePtrDoNotUseDirectly; }
    
    protected:
        Accessor() {}
    
    public:
        // These functions should match Node's public interface
        // Library maintainer must maintain these, but oh well
        inline void addChild(unique_ptr<Node>&& child)) { 
            getNode().addChild(std::move(child));
        }
        inline string getText() const { return getNode().getText(); }
        // ...
    };
    

    Then, a partial template specialization for handling the case of wrapping a “const Accessor”, which is how to signal that it will be receiving a const Node &:

    template<class AccessorType>
    class Wrapper<AccessorType const> {    
    protected:
        AccessorType accessorDoNotUseDirectly;
    private:
        inline AccessorType const & getAccessor() const {
            return accessorDoNotUseDirectly;
        }
    
    public:
        Wrapper () = delete;
        Wrapper (Node const & node) { getAccessor().setNodePtr(&node); }
        AccessorType const * operator-> const () { return &getAccessor(); }
        virtual ~Wrapper () { }
    };
    

    The Wrapper for the “mutable Accessor” case inherits from its own partial template specialization. This way the inheritance provides for the proper coercions and assignments…prohibiting the assignment of a const to a non-const, but working the other way around:

    template<class AccessorType>
    class Wrapper : public Wrapper<AccessorType const> {
    private:
        inline AccessorType & getAccessor() {
            return Wrapper<AccessorType const>::accessorDoNotUseDirectly;
        }
    
    public:
        Wrapper () = delete;
        Wrapper (Node & node) : Wrapper<AccessorType const> (node) { }
        AccessorType * operator-> () { return &Wrapper::getAccessor(); }
        virtual ~Wrapper() { }
    };
    

    A compiling implementation with test code and with comments documenting the weird parts is in a Gist here.


    Sources: @MatthieuM., @PaulGroke

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Note: I've read this and its not quite what I'm looking for: I have
Note: Not sure if this is the right stack, please tell if I should
NOTE: If you don't want to read this, check TLDR version at bottom of
Note: This question was originally part of Magento SOAP API V2 with C#: Issue
Note: This might seem like a Super User question at first, but please read
Note This is not a REBOL-specific question. You can answer it in any language.
Note, this is not a duplicate of .prop() vs .attr() ; that question refers
(Note: This is not a question about what is the best way with code
NOTE: This is a followup to my question here. I have a program that
NOTE: This is an old question and the answers here no longer works (since

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.