Guy Simonsen
Guy Simonsen

Reputation: 123

How to treat derived type as its base type?

I'm wondering if it's possible to treat a class as its base type. I've made a small example below describing the situation i mean.
I use a Vector2 class that I've left out in the example, but it just consists of an x and y value of type float.
I'm trying to make the method called FindEntitiesWithPosition to work with the classes Person and Vechicle, but I get error E0312 no suitable user-defiend conversion from "std::vector<Person, std::allocator<Person>>" to "const std::vector<Entity, std::allocator<Entity>>" exists. How can I make this code work?

class Entity {
public:
    Entity (Vector2 position)
        : position(position) { }

    Vector2 position;
}

class Person : public Entity {
public:
    Person(Vector2 position, std::string name)
        : Entity(position), name(name) { }

    std::string name;
}

class Vehicle : public Entity {
public:
    Vehicle (Vector2 position, int power)
        : Entity(position), power(power) { }

    int power;
}

std::vector<Entity> FindEntitiesAtPosition(std::vector<Entity> entities, Vector2 position) {
    std::vector<Entity> result;
    for (Entity e : entities) {
        if (e.position == position)
            result.push_back(e);
    }
    return result;
}

int main() {
    std::vector<Person> persons;
    persons.emplace_back(Vector2(1.f, 1.f), "Alice");
    persons.emplace_back(Vector2(2.f, 2.f), "Bob");

    std::vector<Vehicle> vehicles;
    persons.emplace_back(Vector2(1.f, 1.f), 3);
    persons.emplace_back(Vector2(2.f, 2.f), 4);

    // Should return person with name "Bob"
    std::vector<Person> v1 = FindEntitiesAtPosition(persons, Vector2(2.f, 2.f));

    // Should return vehicle with power 4
    std::vector<Vehicle> v2 = FindEntitiesAtPosition(vehicles, Vector2(2.f, 2.f));
}

Upvotes: 2

Views: 434

Answers (2)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

You can treat an object of a derived class as an object of a base class. How? You can convert a pointer or a reference to an object of a derived class to a pointer or a reference to an object of a base class, and continue working with the converted pointer or reference. This conversion is implicit so it is a seamless transition from a (single) derived object to its base object. It also works with smart pointers.

Here's the point where things stop being nice. You cannot treat a vector (list, set, vector of vectors, bunch, whatever) of objects of a derived class as a vector (list, set, vector of vectors, bunch, whatever) of objects of a base class. The error message is telling you just that.

Upvotes: 4

prog-fh
prog-fh

Reputation: 16850

template matches your requirements.
I would suggest something like this.

template<typename T>
std::vector<T>
FindEntitiesAtPosition(const std::vector<T> &entities,
                       Vector2 position)
{
  std::vector<T> result;
  for(const auto &e: entities)
  {
    if(e.position == position)
    {
      result.emplace_back(e);
    }
  }
  return result;
}

By the way, watch out the unneeded copies when passing entities and in the range-for loop.

Upvotes: 4

Related Questions