简体   繁体   中英

Can you query same named methods of all inherited classes?

I'm working on a node based structure for defining a creature. Each body part can have "sockets" where you can put things into such as limbs or claws or whatever. To ease future development, it would be good if i could piece together classes from partial ones and have their methods work in conjunction. For instance:

struct Generic {
    vector<Generic*> GetSockets() {return vector<Generic*>();}
}
typedef Generic* GenSock;

struct Bipedal {
    GenSock LeftLeg;
    GenSock RightLeg;
    vector<Generic*> GetSockets() {
        vector<Generic*> ret;
        ret.push_back(RightLeg);
        ret.push_back(LeftLeg);
        return ret;
    }
}

struct TripleHeaded {
    GenSock Head1;
    GenSock Head2;
    GenSock Head3;
    vector<Generic*> GetSockets() {
        vector<Generic*> ret;
        ret.push_back(Head1);
        ret.push_back(Head2);
        ret.push_back(Head3);
        return ret;
    }
}

struct CrazyAlienTorso : Generic, Bipedal, Tripleheaded {
    vector<Generic*> GetSockets() {
        somehow call getsockets from all inherited classes and combine the vector for a single output
    }
}

Is that at all possible?

Otherwise I could of course write out the sockets on each leaflet class manually but as I get more specific with the abstraction, this will likely become very tedious.

Maybe something like this would work for you?

struct CrazyAlienTorso : Generic, Bipedal, Tripleheaded {
    vector<Generic*> GetSockets() {
        vector<Generic*> v1 = Bipedal::GetSockets();
        vector<Generic*> v2 = TripleHeaded::GetSockets();
        v1.insert(v1.end(), v2.begin(), v2.end());
        return v1;
    }
}

There is no way (as far as I know, though they might be working on one for a later version of C++) to enumerate all of the direct bases of a class. Aside from that, though, Kupiakos' answer should work well. If you need to do this sort of thing a bunch of times and have tons of base classes that you need to incorporate, you can do a bit of template metaprogramming to get a slightly cleaner shortcut:

template <typename Base, typename... OtherBases>
struct socket_collector {
    template <typename Derived>
    static void add_sockets(Derived* obj, vector<Generic*>& sockets) {
        socket_collector<OtherBases...>::add_sockets(obj, sockets);
        auto new_sockets = static_cast<Base*>(obj)->GetSockets();
        sockets.insert(end(sockets), begin(new_sockets), end(new_sockets));
    }
};
template <typename Base> struct socket_collector<Base> {
    template <typename Derived>
    static void add_sockets(Derived* obj, vector<Generic*>& sockets) {
        auto new_sockets = static_cast<Base*>(obj)->GetSockets();
        sockets.insert(end(sockets), begin(new_sockets), end(new_sockets));
    }
};
template <typename... Bases, typename Derived>
vector<Generic*> collect_sockets(Derived* obj) {
    vector<Generic*> sockets;
    socket_collector<Bases...>::add_sockets(obj, sockets);
    return sockets;
}

//...

vector<Generic*> CrazyAlienTorso::GetSockets() {
    return collect_sockets<Generic, Bipedal, TripleHeaded>(this);
}

Of course, the main question is what the intended use of GetSockets is: depending on the task that you're trying to accomplish, there might be a better way to structure the code that doesn't involve as much problematic OOP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM