views:

437

answers:

4

I have a class MyClass. I am exaggerating here, but let's say MyClass has 1000 instance variables. I then create a subclass called MySubClass with all the instance variables MyClass has, plus one more.

Question: given an object MyObj of class MyClass, is there an easy way to create a corresponding object MyDerivedObj of class MySubClass, such that the instance variables of MyDerivedObj are the same as the instance variables of MyObj? By "the same", I mean strongly the same, in the sense that if an instance variable of MyObj is a pointer to an object, the corresponding instance variable of MyDerivedObj should point to the same memory.

A: 

It the ivars are marked as @public or @protected, yes, they will be exactly the same.

Adrian Kosmaczewski
But then how do I do the assignment of MyDerivedObj? What I am looking for is a quick way to set all 1000 ivars.
William Jockusch
Use an array...
Adam Woś
+1  A: 

Inherently, every instance of an object will have a different id; a different address and a different allocation point in the heap.

Thus, the instance variables of A and the instance variables of B are always going to be at different locations.

Now, there is no reason why the instance variables of A and B can't be wrapped into a struct that is allocated separately. With that, then A and B could both have an instance variable that is a pointer to a single copy of a structure full of values.

In terms of setting all 1,000 ivars, it depends on what you want to set them too. If 0, then they will be set that way automatically on object instantiation. If you want to bcopy() in a templated set of values, I would suggest that you use a pointer to a structure and do a separate allocation. There is no way to bulk-set an object's instance variables without making assumptions about layout that will eventually bite you.

bbum
+1  A: 

Do those ivars all have to be separate? If I had a similar problem, my first instinct would be to wrap them up in some sort of collection ivar (NS(Mutable)Array/Dictionary/Set) and then you can have a normal getter/setter on it and just do

myDerivedObj.collection = myObj.collection;

Assuming the collection was a property on MyObj class with "assign" memory management policy, I think this should preserve the memory reference.

(I'm still kind of new to this, so shoot down any flaws/errors in my logic.)

Jaanus
Agreed, this looks like a question that hints at a much bigger problem. WHO needs a thousand instance variables in a class ??!!
Adam Woś
I don't have 1000 ivars. I was exaggerating to make the basic issue clear. The main point is that the ivars are numerous enough (and the base class is still likely enough to change) that if I would have to copy them one by one, what I should instead do is approach the whole thing without subclassing.
William Jockusch
A: 

I suggest you create a 'copy constructor' style initialiser for the parent class MyClass, and invoke that from the child class MyDerivedClass initialiser.

[MyDerivedClass initByCopying:someMyObject plusSomeNewProperties:stuff] ->
  [MyClass initByCopying:someMyObject] ->
    [NSObject init] -> // alloc, etc.

Here's some pseudocode:

@interface MyClass : NSObject { 
  int AA;
  // ...
  int ZZ;
}   
@end

@implementation MyClass

-initByCopying:(MyClass*)other;
{
  if (self = [super init])
  {
    self.AA=other.AA;
    //...
    self.ZZ=other.ZZ;
  }
  return self;
}

@end

@interface MyDerivedClass {
  int AAA;
}
@end

@implementation MyDerivedClass 

-initByCopying:(MyClass*)other withNewValue:(int)newVar;
{
  if (self = [super initByCopying:(MyClass*)other])
  {
    self.AAA = newVar;
  }
  return self;
}

@end

I suspect that if you have 1000 member items you might want to consider using a property bag or kvc for all but the performance sensitive ones, which will make your initByCopying routine much simpler.

There may be a shortcut to implementing the copy constructor using the copy protocol, but I couldn't see how to make it easier than the example I gave above.

Alex Brown