Reputation: 1165
This is getting weird. Ship inherits from Entity and MerchantShip from Ship, other types are to be added later, but the basic idea, and what is asked by the professor, is that I use polymorphism, so that I can work on a collection of the main class (pointer with allocated memory used as an array in my implementation), thus there is a virtual void update in all three of the later classes. In fact I have used all combinations of virtual and non-virtual functions that could make sense. Code:
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
class Entity
{
public:
int x, y;
virtual void update() = 0;
void print()
{
cout << "x:" << x << ", y:" << y << endl;
}
};
class Ship: public Entity
{
public:
virtual void update()
{
Move();
}
void Move(){x++;};
};
class MerchantShip: public Ship
{
public:
void update()
{
DontMove();
}
void DontMove(){};
};
int main(int argc, char* argv[])
{
int EntityNumber = 2;
Entity* entities;
entities = (Entity*)malloc(EntityNumber*sizeof(Entity));
for (int i = 0; i < EntityNumber; i++)
{
entities[i].print();
entities[i].update();
entities[i].print();
cout << endl << "next ship: " << endl;
}
system("PAUSE");
return 0;
}
Ok, so it compiles great (stdafx.h is only needed in Visual Studio) but I get a runtime error, which is an access violation at 0xffffffffffffffff when it tries to get into the overridden update functions. In the debug information it consistently looks like the virtual function pointer (__vfptr) is pointing clearly elsewhere than where it should be (0xcdcdcdcdcdcdcdcd), and it's always the same location, even in another code I tried to do the same thing.
Research so far: cause #1 (does not apply): uses function in a DLL that was freed before being called cause #2 (again does not apply): programmer forgets to inherit. I have not come across any other issue in any threads with the same problem, and I've been debugging for a couple of days. If I remove override it will just call the Base class's function. Any clues?
Upvotes: 2
Views: 2075
Reputation: 9406
malloc
does not create and initialize an object but just reserves a block of memory. In C++, you should stay away from manually allocated dynamic arrays and use std::vector
instead
#include "stdafx.h"
// these headers are discouraged. Use cstdlib and cstdio instead.
//#include <stdlib.h>
//#include <stdio.h>
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Entity
{
public:
int x, y;
virtual void update() = 0;
void print()
{
cout << "x:" << x << ", y:" << y << endl;
}
virtual ~Entity() {} // any base-class should have this
};
class Ship: public Entity
{
public:
virtual void update()
{
Move();
}
void Move(){x++;};
};
class MerchantShip: public Ship
{
public:
void update()
{
DontMove();
}
void DontMove(){};
};
int main(int argc, char* argv[])
{
int EntityNumber = 2;
std::vector<std::unique_ptr<Entity>> entities(EntityNumber);
// the array is empty so you have to create some objects in it
entities[0] = new MerchantShip;
entities[1] = new Ship;
for (int i = 0; i < EntityNumber; i++)
{
entities[i].print();
entities[i].update();
entities[i].print();
cout << endl << "next ship: " << endl;
}
system("PAUSE");
return 0;
}
I have also added a virtual destructor to your base class.
Upvotes: 1
Reputation: 36401
You should not use malloc
to allocate C++ object. new
is the correct operator for this.
You will not be able to instantiate Entity
as it is an abstract class.
What you need is an array of pointers to Entity
and associate to them address of concrete Entity
(Ship
or MerchantShip
), like this:
typedef Entity *PEntity;
PEntity entities[2];
entities[0] = new Ship();
entities[1] = new MerchantShip();
Then polymorphism will apply correctly when you will call virtual method via pointers:
for (int i=0; i<2; i++) {
entities[i]->print();
entities[i]->update();
entities[i]->print();
}
What is really important is to understand that there is no Entity
here, just specific Entity
. Entity
is just a concept; Ship
(or MerchantShip
) is one of its concrete realization. You can manipulate concrete objects via their abstract interface.
Upvotes: 4