Specifying base class order with multiple inheritance?

Discussion in 'C++' started by alan, Jul 31, 2008.

  1. alan

    alan Guest

    Hello all, I'd like to know if there was some way I could assure the
    order of base classes.

    To be specific, I have a basemost class Generic:

    class Generic{
    private:
    Generic* to_ptr;
    public:
    virtual size_t get_size() const =0;
    virtual Generic* clone(Semispace&) const =0;
    // gets bits of the class that refer to other
    // Generic objects.
    virtual void get_refs(std::stack<Generic**>&){/*default no
    references*/}
    virtual ~Generic(){}
    /*....*/
    }

    This base class is used intrusively by a copying-GC memory manager
    I've built which handles Generic* objects in a heap, and is complex
    enough that I would prefer to post it only if it's deemed really,
    really necessary.

    I've recently thought of some way to reduce memory consumption, mostly
    by specifying that some objects are trivially reusable - an operation
    which would create a new version of the object could actually reuse
    the old object. Of course, an object might be referred to by some
    other non-reusable object, so it must be marked as "nonreusable" and
    can't be reused.

    So I've defined a Reusable class which specifies that certain classes
    are potentially reusable:

    class Reusable{
    private:
    bool nonreusable;
    public:
    bool reusable(void){return !nonreusable;}
    void banreuse(void){
    //ignore call if already nonreusable
    if(nonreusable) return;
    nonreusable = 1;
    Generic* tmp = dynamic_cast<Generic*>(this);
    if(tmp){
    //ban also the references
    std::stack<Generic**> refs;
    tmp->get_refs(refs);
    while(!refs.empty()){
    Reusable* tmp2 =
    dynamic_cast<Reusable*>(*stack.top());
    if(tmp2) tmp2->banreuse();
    stack.pop();
    }
    }
    }
    };

    So for example I might have a boxed integer class that could be
    reused:

    class Integer : public Generic, public Reusable{
    protected:
    Integer(Integer const& o) : val(o.val), Generic(), Reusable(){}
    public:
    virtual size_t get_size(void){return sizeof(Integer);}
    virtual Integer* clone(Semispace& sp) const {return new(sp)
    Integer(*this);}
    };

    I also have a bunch of classes that *can't* be reused:

    class Closure : public Generic{
    protected:
    std::vector<Generic*> dat;
    Closure(Closure const& o) : dat(o.dat), Generic() {}
    public:
    virtual size_t get_size(void){return sizeof(Closure);}
    virtual Closure* clone(Semispace& sp) const {return new(sp)
    Closure(*this);}
    virtual void get_refs(std::stack<Generic**>& st){
    for(size_t i = 0; i < dat.size(); ++i){
    st.push(&dat);
    }
    }
    explicit Closure(size_t sz) : dat(sz), Generic() {}
    Generic* get(size_t ind){return dat[ind];}
    // enforce invariant: nonreusable object can't point to
    // reusable object, so make the reusable object nonreusable
    virtual Generic* set(size_t ind, Generic* val){
    dat[ind] = val;
    Reusable* tmp = dynamic_cast<Reusable*>(val);
    if(tmp) tmp->banreuse();
    }
    }

    And I have a reusable class that's derived from a class that can't be
    reused:

    class KClosure : public Closure, public Reusable{
    protected:
    KClosure(KClosure const& o) : Closure(o), Generic() {}
    public:
    virtual size_t get_size(void){return sizeof(KClosure);}
    virtual KClosure* clone(Semispace& sp) const {return new(sp)
    KClosure(*this);}
    explicit KClosure(size_t sz) : Closure(sz), Generic(){}
    // enforce the invariant only if we're not reusable
    virtual Generic* set(size_t ind, Generic* val){
    if(!reusable()) Closure::set(ind, val);
    else dat[ind] = val;
    }
    };

    My concern, however, is that my memory manager will work correctly
    only if the start of all objects derived from Generic corresponds to a
    Generic; that is:

    KClosure* kp = some_valid_value();
    assert(((void*) static_cast<Generic*>(kp)) == ((void*) kp));

    So, I'm wondering two things:

    1. is my solution above at all crazy?, and

    2. can I ensure that the Generic base is at the start of the object?
    I would assume that if Generic and derived-only-from-Generic is listed
    as the first class in the inheritance list, it would be positioned to
    the start of the object.
    alan, Jul 31, 2008
    #1
    1. Advertising

  2. On 2008-07-31 08:31, alan wrote:
    > Hello all, I'd like to know if there was some way I could assure the
    > order of base classes.


    >
    > My concern, however, is that my memory manager will work correctly
    > only if the start of all objects derived from Generic corresponds to a
    > Generic; that is:
    >
    > KClosure* kp = some_valid_value();
    > assert(((void*) static_cast<Generic*>(kp)) == ((void*) kp));
    >
    > So, I'm wondering two things:
    >
    > 1. is my solution above at all crazy?, and
    >
    > 2. can I ensure that the Generic base is at the start of the object?
    > I would assume that if Generic and derived-only-from-Generic is listed
    > as the first class in the inheritance list, it would be positioned to
    > the start of the object.


    AFAIK the only thing that the C++ standard says about how classes are
    laid out in memory is the order of its members, which leaves the rest up
    to the discretion of the compiler vendor. This means that you might get
    your solution to work on some compiler, but you can never be sure it
    will work on some other compiler or some other version of the same
    compiler (or for that matter, if you change the compiler options).

    --
    Erik Wikström
    Erik Wikström, Jul 31, 2008
    #2
    1. Advertising

  3. alan

    James Kanze Guest

    On Jul 31, 8:31 am, alan <> wrote:
    > I'd like to know if there was some way I could assure the
    > order of base classes.


    [...]
    > So, I'm wondering two things:


    > 1. is my solution above at all crazy?, and


    I'm not sure I fully understand it, but...

    > 2. can I ensure that the Generic base is at the start of the
    > object?


    No. There are absolutely no guarantees with regards to how the
    compiler lays out base classes in objects.

    > I would assume that if Generic and derived-only-from-Generic
    > is listed as the first class in the inheritance list, it would
    > be positioned to the start of the object.


    In some implementations, that might be, provided no virtual
    inheritance is involved (although in a scheme like yours,
    virtual inheritance will almost certainly be involved at some
    point). But it's certainly not guaranteed, and I believe that
    there are (or were) some compilers that put the base class after
    the first derived class. (I think the goal was to get the
    object pointer pointing to the middle of the object, so you
    could use negative offsets, as well as positive, and have bigger
    objects with the offset only a byte.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jul 31, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ronnie
    Replies:
    4
    Views:
    420
    Ronnie
    Nov 19, 2003
  2. Ian
    Replies:
    7
    Views:
    4,430
    Chris Theis
    Feb 12, 2004
  3. Robert Swan
    Replies:
    2
    Views:
    376
    Greg Schmidt
    Nov 30, 2004
  4. Markus Bertheau

    Multiple inheritance with a common base class

    Markus Bertheau, Aug 10, 2004, in forum: Python
    Replies:
    0
    Views:
    312
    Markus Bertheau
    Aug 10, 2004
  5. Markus Bertheau
    Replies:
    5
    Views:
    620
    Duncan Booth
    Aug 10, 2004
Loading...

Share This Page