accessing protected data members of instance of parent class

Discussion in 'C++' started by Suzanne Vogel, Dec 7, 2003.

  1. Hi,

    Given: I have a class with protected or private data members, some of
    them without accessor methods. It's someone else's class, so I can't
    change it. (eg, I can't add accessor methods to the parent class, and I
    can't make some "helper" class a friend of the parent class to help in
    accessing the data.)

    Problem: I want to derive a class that has a copy constructor that
    properly copies those data members.

    What I tried:
    1. I tried using memcpy() to copy all the data members. That always
    crashed if the derived class contained virtual functions (?!), and
    sometimes even more times than that.

    class Derived
    {.....
    public:
    Derived(Parent& rhs)
    {
    memcpy(this, &rhs, sizeof(Parent));
    }
    }

    *** What gives? Why doesn't this work?
    I'm guessing I'm not copying rhs into the proper portion of Derived's
    memory layout. :-/

    2. I tried static_casting the parent class to the derived class, so that
    I could gain access to its data members directly.

    class Derived
    {.....
    public:
    Derived(Parent& rhs)
    {
    dataMemberX = static_cast<Derived&>(rhs).dataMemberX;
    }
    }

    *** Is this *safe*? ie, Is it safe to static_cast from one instance down
    to a *derived* class, even if that instance wasn't originally created of
    the derived type?

    Seems to me that sometimes this will work (as it has every time I've
    *tried* it), and sometimes I'll get a mem access exception because the
    derived class is bigger than the parent class.

    3. *** Anyone have better suggestions for what else I might try? ;-)
    Hacks are welcome, as long as they're "safe".

    Thanks!
    Suzanne
     
    Suzanne Vogel, Dec 7, 2003
    #1
    1. Advertising

  2. "Suzanne Vogel" <> wrote in message
    news:3fd367b2$...
    | Given: I have a class with protected or private data members, some of
    | them without accessor methods. It's someone else's class, so I can't
    | change it. (eg, I can't add accessor methods to the parent class, and I
    | can't make some "helper" class a friend of the parent class to help in
    | accessing the data.)
    |
    | Problem: I want to derive a class that has a copy constructor that
    | properly copies those data members.
    |
    | What I tried:
    | 1. I tried using memcpy() to copy all the data members.

    This leads to undefined behavior (except for PODs=C-like structs).


    | 2. I tried static_casting the parent class to the derived class,
    | so that I could gain access to its data members directly.
    ....
    | *** Is this *safe*? ie, Is it safe to static_cast from one instance down
    | to a *derived* class, even if that instance wasn't originally created of
    | the derived type?

    No, formally not. Although it will work on many implementations if you
    only access base class members and avoid any virtual/dynamic methods.


    | 3. *** Anyone have better suggestions for what else I might try? ;-)
    | Hacks are welcome, as long as they're "safe".

    You haven't said wheter the Parent class had an accessible
    copy-constructor.
    But the nice clean way to do it is:
    class Derived : public Parent // this relationship assumed
    {.....
    public:
    Derived(Parent& rhs)
    : Parent( rhs ) // initialize Parent sub-object with rhs
    {
    // ... whatever else is needed ...
    }
    };


    I hope this helps,
    Ivan
    --
    http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
     
    Ivan Vecerina, Dec 7, 2003
    #2
    1. Advertising

  3. > | Given: I have a class with protected or private data members, some of
    > | them without accessor methods. It's someone else's class, so I can't
    > | change it. (eg, I can't add accessor methods to the parent class, and I
    > | can't make some "helper" class a friend of the parent class to help in
    > | accessing the data.)
    > |
    > | Problem: I want to derive a class that has a copy constructor that
    > | properly copies those data members.


    [snip]

    > | 3. *** Anyone have better suggestions for what else I might try? ;-)
    > | Hacks are welcome, as long as they're "safe".
    >
    > You haven't said wheter the Parent class had an accessible
    > copy-constructor.


    No, the parent class does not have a copy constructor -- or even an
    assignment operator. :-( But thanks for the suggestion.

    *** Any suggestions that do *not* require the parent to have a copy
    constructor or assignment operator?

    eg, I have an idea: I've broadened my scope from requiring copying done
    within the copy constructor, to permitting it down from outside. The
    difference here is that I'm typecasting the derived instance *up* to the
    parent class (rather than trying to typecast the parent down to the
    derived class, which is unsafe).

    *** Is this safe & guaranteed to work in all cases?

    Parent* p = new Parent(...);
    Derived* d = new Derived();
    memcpy(static_cast<Parent*>(d), p, sizeof(Parent)); // copy p to d

    Thanks again!

    Suzanne

    > But the nice clean way to do it is:
    > class Derived : public Parent // this relationship assumed
    > {.....
    > public:
    > Derived(Parent& rhs)
    > : Parent( rhs ) // initialize Parent sub-object with rhs
    > {
    > // ... whatever else is needed ...
    > }
    > };
    >
    >
    > I hope this helps,
    > Ivan
     
    Suzanne Vogel, Dec 8, 2003
    #3
  4. "Suzanne Vogel" <> wrote in message
    news:...
    | > You haven't said wheter the Parent class had an accessible
    | > copy-constructor.
    |
    | No, the parent class does not have a copy constructor -- or even an
    | assignment operator. :-( But thanks for the suggestion.

    Sorry to be picky here, but you have to be specific.
    If the parent class doesn't have (*declare*) a copy-constructor or
    assignment operator, a default compiler-generated implementation
    of these functions will exist and be accessible.
    If the parent class defines them as public or protected members,
    they can only be used.
    Only if those members are declared as private will you not
    be able to use the solution I suggested.

    | *** Any suggestions that do *not* require the parent to have a copy
    | constructor or assignment operator?

    If both of these operations as declared as *private* in the parent,
    the C++ standard will not allow you to portably work around the
    intent of what has been written.

    | *** Is this safe & guaranteed to work in all cases?
    |
    | Parent* p = new Parent(...);
    | Derived* d = new Derived();
    | memcpy(static_cast<Parent*>(d), p, sizeof(Parent)); // copy p to d

    I would stay away from memcpy. It does lead to real problems
    (not only in theory, though it depends on the contents of Parent).

    If you really need a hack, the following might be more
    reliable:

    // File: Derived.cpp
    #define private public //illegal, but typically works in practice...
    #include "Parent.h"
    #undef private
    //... other includes ...
    // and use the copy-constructor of Parent,
    // as suggested in my previous reply

    hth -Ivan
    --
    http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
     
    Ivan Vecerina, Dec 8, 2003
    #4
  5. > | No, the parent class does not have a copy constructor -- or even an
    > | assignment operator. :-( But thanks for the suggestion.
    >
    > Sorry to be picky here, but you have to be specific.
    > If the parent class doesn't have (*declare*) a copy-constructor or
    > assignment operator, a default compiler-generated implementation
    > of these functions will exist and be accessible.


    (Let's call this the "copy constructor method" -- for the discussion below.)

    Durn, I forgot! *blush* Yes, the parent class doesn't declare a copy
    constructor, so it has the default. The default copy constructor copies
    ptr values, but that's okay because we can write a little method to
    allocate new memory (assigning new ptr values to our new object).

    Thanks! :)

    > I would stay away from memcpy. It does lead to real problems
    > (not only in theory, though it depends on the contents of Parent).


    eg, I found that if some of the data members in Parent are NULL, then
    memcpy() results in a NULL ref exception (even *if* I try to allocate
    new memory to the child data members). Strange.

    > If you really need a hack, the following might be more
    > reliable:
    >
    > // File: Derived.cpp
    > #define private public //illegal, but typically works in practice...
    > #include "Parent.h"
    > #undef private
    > //... other includes ...
    > // and use the copy-constructor of Parent,
    > // as suggested in my previous reply


    (Let's call this the "macro hack method" -- for the discussion below.)

    Ah, yes, defining keywords as macros. (I just saw that done for "new"
    somewhere.) ;-) Dangerous if someone tries to use class Derived in with
    *precompiled* Parent code, I'd think (because then the "private" macro
    wouldn't have been defined when Parent was compiled).

    -------//-------

    FYI, below is my complete test program, hacks and all. Only the copy
    constructor method (and the macro hack method) is 100% reliable. I have
    no questions. :)
    --Suzanne

    #include <iostream>

    #define COUT std::cout
    #define FLUSH std::flush

    #define private public //----- BEGIN HACK -----

    class Parent
    {
    private:
    int* mX;
    protected:
    int* mY;
    public:
    int* mZ;
    public:
    Parent(int* x=NULL, int* y=NULL, int* z=NULL) : mX(x), mY(y), mZ(z)
    {
    if (mX==NULL) mX = new int(3);
    if (mY==NULL) mY = new int(5);
    if (mZ==NULL) mZ = new int(7);
    }
    virtual ~Parent() { delete mX; delete mY; delete mZ; }

    void print() { COUT << "(" << mX << ", " << mY << ", " << mZ << ")\n"
    << "(" << *mX << ", " << *mY << ", " << *mZ <<
    ")\n----------------\n" << FLUSH; }
    };

    #undef private //----- END HACK -----

    class Derived : public Parent
    {
    public:
    Derived() {}


    //*************************************************************************
    // WORKS

    //*************************************************************************
    Derived(Parent& rhs) : Parent(rhs) { fixupPtrs(); }

    //*************************************************************************

    Derived& copy1(Parent& p) // WARNING: Works here iff ptrs are
    non-NULL -- but undefined in general
    {
    memcpy(this, static_cast<Derived*>(&p), sizeof(Derived));
    fixupPtrs();
    return *this;
    }
    Derived& copy2(Parent& p) // WARNING: Works here iff ptrs are
    non-NULL -- but undefined in general
    {
    memcpy(static_cast<Parent*>(this), &p, sizeof(Parent));
    fixupPtrs();
    return *this;
    }
    Derived& copy3(Parent& p) // WARNING: Works here iff "private" is
    macro #define'd as "protected" or "public"
    {
    Derived& d = static_cast<Derived&>(p);
    mX = d.mX!=NULL ? new int(*(d.mX)) : new int(3);
    mY = d.mY!=NULL ? new int(*(d.mY)) : new int(5);
    mZ = d.mZ!=NULL ? new int(*(d.mZ)) : new int(7);
    return *this;
    }
    Derived& copy4(Parent& p) // WARNING: Senseless crap -- and
    sometimes gives NULL ref exception!!
    {
    const_cast<Derived*>(this) = &(Derived(p));
    fixupPtrs();
    return *this;
    }

    private: // Give this object different ptrs from (but the same values
    as) the parent from which it was copied
    void fixupPtrs() { mX = new int(*mX); mY = new int(*mY); mZ = new
    int(*mZ); }
    };

    int main(int argc, char** argv)
    {
    Parent* p = new Parent();
    Derived* d = new Derived();

    COUT << "//////////////////////// Parent: ///////////////////////\n";
    p->print();

    // ----- All of these are *unsafe* -----
    COUT << "//////////////////////// Derived: ///////////////////////\n";
    d->copy1(*p).print();
    d->copy2(*p).print();
    d->copy3(*p).print();
    //d->copy4(*p).print(); // Yeeks, gives NULL ref exception

    // ----- This is *safe* -----
    COUT << "//////////////////////// Derived: ///////////////////////\n";
    Derived* d2 = new Derived(*p);
    d2->print();

    delete p;
    delete d;
    delete d2;
    }
     
    Suzanne Vogel, Dec 8, 2003
    #5
  6. Suzanne Vogel

    Dan W. Guest

    >> // File: Derived.cpp
    >> #define private public //illegal, but typically works in practice...
    >> #include "Parent.h"
    >> #undef private
    >> //... other includes ...
    >> // and use the copy-constructor of Parent,
    >> // as suggested in my previous reply

    >
    >(Let's call this the "macro hack method" -- for the discussion below.)
    >
    >Ah, yes, defining keywords as macros. (I just saw that done for "new"
    >somewhere.) ;-) Dangerous if someone tries to use class Derived in with
    >*precompiled* Parent code, I'd think (because then the "private" macro
    >wouldn't have been defined when Parent was compiled).
    >


    Public, private and protected qualifiers are compile-time only;
    --i.e.: they are not retained in (compiled) object code.

    >#define private public //----- BEGIN HACK -----
    >
    >class Parent
    >{

    ....(snip)...
    >};
    >
    >#undef private //----- END HACK -----


    The above will indeed affect other code using the base class. Do the
    hack in the derived class header file:

    //-----------------------------------------------
    #define private protected //----- BEGIN HACK -----
    #include "parent.h"
    #undef private //----- END HACK -----

    class Derived : public Parent
    {
    ...
    };
    //-----------------------------------------------


    But given that you said that the parent class has its compiler default
    copy constructor intact; I don't see the need to hack it in the first
    place...
     
    Dan W., Dec 9, 2003
    #6
    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. Grey Plastic
    Replies:
    4
    Views:
    843
    pw4getter
    Mar 5, 2004
  2. hdixon
    Replies:
    3
    Views:
    676
    hdixon
    Jul 9, 2006
  3. Mr Dyl
    Replies:
    2
    Views:
    507
    Mr Dyl
    Dec 1, 2005
  4. Replies:
    2
    Views:
    857
    Noah Roberts
    Jun 9, 2006
  5. Rahul
    Replies:
    1
    Views:
    933
    Rahul
    Apr 7, 2008
Loading...

Share This Page