user3079666
user3079666

Reputation: 1165

Access violation in C++ polymorphism (virtual pointer function pointing to wrong place?)

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

Answers (2)

Jens
Jens

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

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

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

Related Questions