• Welcome to Valhalla Legends Archive.
 

Structures and inheritence

Started by Arta, February 19, 2004, 03:04 AM

Previous topic - Next topic

Arta

Is this safe?



struct SBase
{
   int i;
   char c;
};

struct SDerived: public SBase
{
   double d;
};

SBase Base;
SDerived Derived;

memcpy(&Base, (SBase*)&Derived, sizeof(SBase));



The idea being that Base now contains the values i and c from Derived. This seems to work, but I wondered if there might be any complications I should be aware of before I go code things based on the idea.

iago

I wouldn't recommend using C functions (memcpy) with C++ constructs (inheritance).  I don't think it's safe.  I would recommend writing a function in your base class .clone, to rip off java:


SBase::clone(SBase &dest)
{
 dest.i = i;
 dest.c = c;
}

SDerived::clone(SDerived &dest)
{
 super(dest);
 dest.d = d;
}


Then you can cast stuff and make copies and all the fun stuff.  Creating a clone contructor is also a good approach:
SBase a = new SBase(oldSBase);

Those are both better ways, at least in my opinion.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Skywing

I think super is a VC extension, FWIW.

Kp

Alternately, you could implement operator= to let the classes intelligently copy data among themselves.  For a generalized (but less automatically maintained) solution to the issue Skywing points out, replace super (dest) in SDerived::clone with SBase::clone(dest).  It's less automatic since it will break or behave oddly if SBase ever stops being the direct parent of SDerived (even if the stop is because SBase got renamed).
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Arta

Wouldn't a clone function or overloaded operator be rather slower than copying the structure?  Although I understand your hesitation RE mixing C/C++, I guess my real question is how would that inheritence be implemented by the compiler? I'm not keen on adding a clone function or overloaded operator, since changing the structure would then require adding a statement to copy the new variable.

iago

Quote from: Skywing on February 19, 2004, 12:20 PM
I think super is a VC extension, FWIW.

I was thinking in Java again, my apologies.  

Arta - Are you trying to make something that needs ultra speed?  I can't see there being much of a speed difference between assigning the variable manually and a memcpy.

The best way to find out is to try the memcpy, and see if it works.  But be warned - different compilers may act differently for something like this.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Kp

#6
If you're really determined to use memcpy, you might be able to defend against inheritance weirdness by having an inline member in the SDerived as follows:

SBase *base_part() { return this; }

Afaik, the compiler will automatically adjust such an invocation to ensure that the returned pointer really does point at the SBase component.  Also, barring multiple inheritance, the compilers I've used always front-align the parent class so that the inlined function I gave doesn't need to add anything to the pointer.  However, as iago said, there's no guarantee that all compilers will behave the way I observed.

Alternately, you could use static_cast<SBase*>(pSDerived).  I've been using a fair amount of multiple inheritance in some of my code lately, and static_cast takes care of the type-checking + adjusts the pointer to be correct too! :)
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

K

Quote from: Kp on February 19, 2004, 03:19 PM
Alternately, you could use static_cast<SBase*>(pSDerived).  I've been using a fair amount of multiple inheritance in some of my code lately, and static_cast takes care of the type-checking + adjusts the pointer to be correct too! :)

Threadjack: I was under the impression that for conversions between base and derived pointer types that you should use reinterpret_cast?

Skywing

Quote from: K on February 19, 2004, 04:35 PM
Quote from: Kp on February 19, 2004, 03:19 PM
Alternately, you could use static_cast<SBase*>(pSDerived).  I've been using a fair amount of multiple inheritance in some of my code lately, and static_cast takes care of the type-checking + adjusts the pointer to be correct too! :)

Threadjack: I was under the impression that for conversions between base and derived pointer types that you should use reinterpret_cast?
I think you only need to use reinterpret_cast for "strange" casts, like converting an int into a something*.

MyndFyre

Quote from: Arta[vL] on February 19, 2004, 03:04 AM
Is this safe?



struct SBase
{
   int i;
   char c;
};

struct SDerived: public SBase
{
   double d;
};

SBase Base;
SDerived Derived;

memcpy(&Base, (SBase*)&Derived, sizeof(SBase));



The idea being that Base now contains the values i and c from Derived. This seems to work, but I wondered if there might be any complications I should be aware of before I go code things based on the idea.

My only contribution to this is that it seems to be poor OOP programming practice.  memcpy completely tears away any kind of privacy or internal order of the data.  Using memcpy would be considerably faster for a base strucuture that is extremely large, but a two-item copy would probably not give you such a performance drain, even if you did many of them.

For code clarity and a clear OOP conscience, I would recommend rather using a clone member method as (I believe) iago suggested.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Adron

Quote from: Arta[vL] on February 19, 2004, 02:20 PM
Wouldn't a clone function or overloaded operator be rather slower than copying the structure?  Although I understand your hesitation RE mixing C/C++, I guess my real question is how would that inheritence be implemented by the compiler? I'm not keen on adding a clone function or overloaded operator, since changing the structure would then require adding a statement to copy the new variable.

You could use an inline clone function in the base, doing a memcpy if that's what it's supposed to do. Writing a memcpy to copy the base in the derived class is ugly.

Arta

hmmwell, according to one of my lecturers, this should always be safe. Private/public access isn't really an issue since everything is public anyway. Speed is indeed crucial, and, to be honest, I don't see it as being eww. I only ever use structs as 'dumb' types to store collections of data that have something in common, thus, I don't see any eww-ness with using memcpy to copy all the data. Besides which, this design fits so neatly into the system.

I think Kp's suggestion is a good one, but since my lecturer confirmed that the compiler will do that implicitly via the cast, it is perhaps overkill.

Adron

The eww thing comes when you keep using this method for a lot of classes, and eventually decide to add something to the base class which requires a deep copy. Then you have to go around looking for memcpy's and replacing them.

Writing an inline clone/copyconstruct/something function which calls memcpy in the base class will give you the same speed, with a nicer design.

I'm not saying that an appropriate memcpy is eww; what I'm saying is that having a derived class memcpy a base class that should be implemented and reimplementable in a separate file is eww. All that needs to happen for your scheme to be invalid is that you add a std::string or similar to your base class, and then you have to go around to all classes that use your base class and modify the code there, big eww.

Arta

I see what you mean. I think in this case, though, that would never be an issue.

The idea here is to separate two sets of information, but to keep them related. The data (regardless of if it's in the derived or base structure) is information about the state of a connected client. Some of this information must be sent, via TCP/IP, to another machine. That's what I've put in the base structure. The stuff in the derived structure is only ever needed by the machine to which the user is connected, and therefore need not be transmitted. The idea of derived that structure is to allow the server access to both sets of information through one pointer, whilst still allowing other parts of the server to isolate the two structures from each other as needed.

I'd never call memcpy on a class, that would totally suck, but since this will never contain functions, and will always just be a 'dumb' type, it seems ok to me - an exception to the rule. Otherwise I would totally agree with you.

Adron

What is the reason for deriving the class instead of just declaring an instance of the base class inside the other class?