Help me prevent object slicing in this code.

I have a base class GameObject. This class has this function.

1
2
3
4
5
6
7
8
9
10
GameObject* GameObject::Instantiate(GameObject* object, Vector2 position)
{
        //Construct new object
	GameObject* newObject = new GameObject(*object);
        newObject->position = position.
	//Call Start() method for all GameObject derived classes.
	newObject->Start();

	return newObject;
}



Now, this function should return and craete "copy" of the object which was passed into the function.

So if I do.

1
2
3
GameObject ball; //Ball inherits from GameObject

ball = Instantiate(new Ball(), Vector2(0, 0));


Instantiate will return new instance of Ball. Instantaite() is little longer, I just simplified it for this purpose.


The problem I have is, the virtual function Start() of GameObject inside Instantaite() (newObject->Start()) is not called in derived classes of GameObject, since I presume, the object is sliced. Please, is there any way how to solve this problem?

Thanks for any help or suggestions.
Last edited on
is not called in derived classes
Which derived classes are you talking about?

newObject is a GameObject, not some derived class, as you explicitely made it to be it.

If you want to make a complete copy of object of unknown type, you need to use a virtual copy pattern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Base
{
  public:
    virtual Base* clone() { return new Base(*this); }
    virtual void identify() {std::cout << "Base\n"; }
};

class Derived : public Base
{
  public:
    virtual Derived* clone() override { return new Derived(*this); }
    virtual void identify() override {std::cout << "Derived\n"; }
};

//Usage:
Base* foo = new Derived;
Base* bar = foo->clone();
bar->identify();
Derived
http://ideone.com/XAUZKw

http://stackoverflow.com/questions/12255546/c-deep-copying-a-base-class-pointer
Last edited on

is not called in derived classes
Which derived classes are you talking about?


yes, sorry I mean derived classes which inherit from GameObject.
Think of it like I can have enemy, monster, player, animal, but they are all GameObjectS in the game engine, which then all get rendered, perform collision etc.

The instantiate function performs the creation and addition of this GameObject into the game engine and scene, and some other tasks. So I need it to be very generic, and be able to create new objects (animals, monsters, balls) when I call this Instantiate().

I mean derived classes which inherit from GameObject.
I got that, what I was trying to say, that in this line:
GameObject* newObject = new GameObject(*object);
you explicitely creating a GameObject object and not any of the derived classes one.

If you need to copy object from base class pointer, you need to either use virtual constructor (aka clone) pattern I posted before (needs support from all derived classes).
Or use some factory dispatching calls to correct functions using RTTI (slower, requires enabled RTTI, and should be carefully maintained by programmer). On the other side it will give an error if you forget to maintain it, when clone approach gives you wrong object for children of proper clonable classes. You can see example of one here: http://stackoverflow.com/questions/4755105/making-a-copy-of-an-object-of-abstract-base-class
Ball inherits from GameObject
No.

This
GameObject* newObject = new GameObject(*object);
creates a GameObject not whatever object is reffering to (Ball).

As MiiNiPaa hinted: That line above should look like this:
GameObject* newObject = object->clone();
EDIT: Oh God I have it. Thanks to all the support guys.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Creates a new copy of passed game object. Object is added into currently active scene.
	GameObject* GameObject::Instantiate(GameObject* object, const Vector2 position)
	{
		//Construct new object
		GameObject* newObject = dynamic_cast<GameObject*>(object);

		//Create transform of this object
		newObject->transform = new Transform();
		newObject->AddComponent(*newObject->transform);

		//Give the object an position
		newObject->transform->position = position;

		//Call Start() method for all GameObject derived classes, object is ready to use
		newObject->Start();

		return newObject;
	}



Dynamic cast saved the day(again :D).
Last edited on
No, C++ does not have actual facility to do that. I mean, Instantiate does not know about actual type of object you pass to it, so you need to tell it in some way about it.

Clone approach is to-go way to do that in most cases. I often even see something like macro
1
2
3
4
class foo : public base
{
    DECLARE_CLONABLE(foo);
//... 
widely used to avoid need to manually override method each time.

Another way is, as I said, is to have factory which dispatches object creation using RTTI. There maintenance is usually comes to adding a single line or macro call to specific function too.

Edit: Another article on it: https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/

Edit 2: @ne555 :D. Beats me to it.

@wrymn you do not do object copy here (and dynamic cast is not doing anything at all here) so of cource it will work: you are operating on original
Last edited on
Topic archived. No new replies allowed.