Copying objects

I have a std::vector with pointers to objects. The objects are instances from either the class Block or one of its subclasses called Target and Box. Also, I've defined a "regular" array with pointers to objects of the same size of the amount of objects in the vector.

1
2
3
std::vector<Block *> blocks;
//Inserted some Block-instances, or instances of one of its subclasses here...
Block ** lvlBlocks = new Block * [blocks.size()];


Now, I want to create a copy of all the objects the vector's pointers point to. I want to store these pointers of those copies in the array "lvlBlocks".

How should I copy those objects?

Also, I need to determine if the object in that array is an instance of Block, Target or Box. Is that possible? How should this be done? In Java, I would use:
if(object instanceof Target) {...}

I need to be able to access the methods of Target and Box later.
Last edited on
Sounds like a job for the clone pattern:

http://www.cplusplus.com/forum/articles/18757/
Offtopic:
1
2
3
4
struct clonable {
    virtual ~clonable() {}
    virtual clonable* clone() const = 0;
};


Why is it defined as a struct and not a class?
And why is the deconstructor virtual?

But i'm going to try that one. Tnx. :)

edit:
1
2
3
4
5
6
7
Block ** lvlBlocks = new Block * [this->blocks.size()];
	
int i=0;
for(std::vector<Block *>::iterator blockIterator = this->blocks.begin();
	blockIterator != this->blocks.end();
	blockIterator++)
	lvlBlocks[i++] = (**blockIterator).clone();


That did work out well :)
Thanks :)
Last edited on
When using the struct keyword, all members are public by default (instead of private).
The destructor should be virtual so that the object is deleted properly when using delete on a clonable pointer pointing to an instance of a derived class.

As for checking the class, you can use if (dynamic_cast<Target*>(object)) {...}
Although with a proper design, this is usually unnecessary . Make sure the derived class' function that you want to call shouldn't be part of the base class and that there is no other solution to the problem.
Why is it defined as a struct and not a class?


class/struct is just a style issue. Really the only difference between the two is that structs default to public members while classes default to private.

And why is the deconstructor virtual?


Virtual destructors ensure that the derived class's dtor will be called if the object is destroyed via a parent pointer. A general rule of thumb is that if a class has any virtual members, it should also have a virtual destructor.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Parent
{
public:
  ~Parent() { cout << "Parent dtor called\n"; }
};

class Child : public Parent
{
public:
  ~Child(){ cout << "Child dtor called\n"; }
};


int main()
{
  Parent* p = new Child;
  delete p;  // calls Parent dtor, but not Child dtor!
     // this could be very bad!
     // however, both child and parent dtor is called if the 
     //  destructor is virtual
}




EDIT:

As for checking the class, you can use if (dynamic_cast<Target*>(object)) {...}


True, you can do that. But EEEW!

Downcasting is evil and should be avoided.
Last edited on
So... if the superclass has a virtual deconstructor and the childclass has a regular deconstructor, BOTH methods will be called?

What if both both are virtual?
What if the childclass doesn't have a deconstructor?

I'm going to look for some more information about the virtual keyword...
Last edited on
Once virtual, always virtual. The child class' destructor will be virtual even if you omit the virtual keyword.

What if the childclass doesn't have a deconstructor?

That can never happen. If necessary, the compiler will generate a default destructor.

I'm going to look for some more information about the virtual keyword...

Don't you know anything about virtual at all? That would explain why you're trying to figure out object types.
You definitely should make sure you understand polymorphism before continuing, you might find that this makes things much easier.
I know you can override methods with the virtual keyword. That's about my knowledge about the virtual keyword.
I didn't know you can't determine an object's type at runtime...

I just found out that it's not possible to determine whether the instance is an instance of Block or an instance of one of its subclasses, unless you keep track of the class yourself some way, like by adding an additional virtual method returning the class-id, like Java's getClass method.

Actually, I think that's a good thing. This is why I like C++: you have complete control with everything; you can choose whether your objects should keep track of their own class-id or not.
Last edited on
I didn't know you can't determine an object's type at runtime...


You can. You just typically shouldn't.

I just found out that it's not possible to determine whether the instance is an instance of Block or an instance of one of its subclasses,


It is possible with typeid(). But again... you typically shouldn't do this.
1
2
3
4
5
6
7
class A {}
class B: public A {}

A * b1 = new A();
A * b2 = new B();
cout << typeid(b1).name(); // Will return something like "A"
cout << typeid(b2).name(); // Will also return the same 


AFAIK, you can't determine whether it's an A instance or a B instance; typeid returns the type of the pointer variable, not the type of the object it refers to.

But why shouldn't this be done? There is not much left of OOP if you shouldn't determine an object's type IMO.

Any recommended articles about OOP in C++?
I'm currently reading this one:
http://www.gillius.org/ooptut/part1.htm#Thinking%20in%20OOP

I'm going to read some more C++ specific OOP articles.
Last edited on
Regarding your example...

1) That's true if the classes are not polymorphic. If they are polymorphic, though, you can determine the type with typeinfo. A polymorphic class has at least 1 virtual member or virtual parent. (In Java everything is polymorphic so it's moot).

2) name() isn't the only means by which to identify the type. And in fact, it's unreliable as different compilers will yield different results.

Here's a example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <typeinfo>

using namespace std;

class A
{
public:
    virtual ~A() { }  // virtual dtor to make it polymorphic
};

class B : public A {};

int main()
{
    A* b1 = new A;
    A* b2 = new B;

    if(typeid(*b1) == typeid(B))  cout << "b1 is a B" << endl;
    else                          cout << "b1 is not a B" << endl;

    if(typeid(*b2) == typeid(B))  cout << "b2 is a B" << endl;
    else                          cout << "b2 is not a B" << endl;

    cin.get();
	return 0;
}



But why shouldn't this be done? There is not much left of OOP if you shouldn't determine an object's type IMO.


It's actually the opposite. OOP is destroyed if you need to know the exact type.

The whole point of abstracting with a parent class is so that you can write code to work with any derived class. If you're determinig the type and/or downcasting, you're no longer writing code that is adaptable to different types.

Let's take the classic Area() example. Say you have a parent class "Shape" and derived classes "Rectangle" and "Circle". And say you have a function that takes a Shape* pointer and needs to calculate and print the area of that shape:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// area of rectangle = width*height
// area of circle = pi*radius*radius

// now you might think that since the area for each shape is calculated a different way, that you need
//  to determine what kind of shape it is and calculate the area based on that:

void printArea(Shape* shape)
{
  int area;
  if( typeid(*shape)  == typeid(Circle) )  // is the shape a circle?
  {
    // if yes...
    Circle* c = static_cast<Circle*>(shape);  // downcast so we can access Circle members
    area = c->radius * c->radius * pi;  // calc the area
  }
  else if( typeid(*shape) == typeid(Rectangle) )
  {
    // otherwise, if the shape is a rectangle
    Rectangle* r = static_cast<Rectangle*>(shape);  // downcast
    area = r->width * r->height;
  }

  cout << "The area is:  " << area;
}


Of course, this is the absolute wrong way to do this. Determining the type and downcasting has a big problem. It forces you to write code that will only work with specific classes.

What happens, for example, if a new shape 'Triangle' is created later. You would have to remember to update this function. But what if you're doing this in dozens of different areas in your program? Every time you add a new shape, you have to go back and modify each and every spot that checks the type. Hope you don't forget any!


The better way is to take advantage of polymorphism. Instead of determining the type, just deal with an abstract interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Shape
{
public:
  virtual int Area() = 0;  // virtual function to calculate the area
};

class Circle
{
  int radius;
public:
  virtual int Area() { return radius * radius * pi; }
};

class Rectangle
{
  int width, height;
public:
  virtual int Area() { return width * height; }
};

//===================

void printArea(Shape* shape)
{
  // now, it doesn't matter what kind of Shape we have... we can just do this:
  cout << "The area is:  " << shape->Area();
}


printArea doesn't need to know what kind of shape it has. All it needs to know is that it has some kind of Shape, and that Shapes have a way to calculate their area. The more the function assumes about the type, the less flexible it becomes.


This new printArea function not only works with Circles and Rectangles, but it will also work with any and all shapes that may be created in the future. If you add a new shape, this function will work with it without any modifications.


Here's another post I made a little while ago that goes into more detail:

http://cplusplus.com/forum/beginner/28170/#msg152257
Thanks for the huge post.

The typeid().name was just an example to show both will return the same name; I already noticed the returned string is mostly garbage

I have 3 classes:

A base-class, named Block
A second class, named Targeted
A child-class of Block and Targeted, named BoxTarget
and a second child-class of Block and Targeted, named Box.

The array above contains pointers to Block instances, and instances to any subclass of Block, including BoxTarget and Box.

Now, I need to iterate through all Block-instance and execute virtual methods that are defined in Targeted... So, I want to check if the given Block is an instanceof Targeted, cast the object to a Targeted, and then execute Targeted-specific methods.

Maybe this is a wrong application design, but I couldn't think of a better design... but that's why I'm still learning OOP.

edit:
btw, your "wrong way" works. Thanks :)
typeid(*variable) did the trick.
Last edited on
The typeid().name was just an example to show both will return the same name; I already noticed the returned string is mostly garbage


Well part of my point was that typeid().name of two different objects might match even if the types are actually different.

it's better to just compare the typeid() to another typeid() instead of comparing the name, as I did in my example.

So, I want to check if the given Block is an instanceof Targeted, cast the object to a Targeted, and then execute Targeted-specific methods.


This is the exact same thing as the "wrong way to do the Area()" that I illustrated above.

If you have an array of Blocks, you should be treating them all like Blocks.

If you need to treat them like Targeteds, then you should have an array of Targeteds instead.

Or, if it makes sense, put the virtual function in Blocks so that you can call it from your array of blocks without having to downcast. But it's hard to say whether or not that makes sense without knowing exactly what it is you're doing.

How about this:

1) What do Block and Targeted represent in your program? Like what are they and what are the differences between them.
2) What function(s) in Targeted do you need to call from your array of Blocks, and what does that function do?
Last edited on
You know, by know, I tried to explain my application design... but I just realized I can't because the design is just wrong.

Normally, I would throw away everything and redesign the whole app... but I put quit a lot of hours creating my first C++ app and it's working finally, so forgive me for not throwing this away :P
hah. That's fine. ^^

You'll be a little wiser for the next app ;D
Topic archived. No new replies allowed.