tags:

views:

112

answers:

4

I think I messed up somehow in my design because I want to keep a vector of various object types. These types all share a common base class. Example:

Class Buick: AmericanCar
{
}

Class Ford: AmericanCar
{
}

then I did:

vector<AmericanCar*> cars_i_own;

Now, I have my vector of pointers but I don't have the derived class which is what I need. I thought about adding a GetType/SetType function to the base class and then use a dynamic cast. This is clunky though. Did i use the wrong design for this?

A: 

You can use typeid to determine the derived class:

struct Base
{
 virtual ~Base() {} 
};

struct Derived : public Base { };

int main()
{
 Base* b = new Derived();
 std::cout << typeid(*b).name() << std::endl;
}

This outputs: "Derived".

But, usually with polymorphism the point is that you shouldn't be concerned with this. You simply call a base-class member function and the proper derived-class member function is called at runtime.

Charles Salvia
I don't think this is guaranteed by the standard. The result of name() is implementation-defined IIRC.
sellibitze
It is indeed, though I think any usable compiler will fill out the name.
GMan
The actual string returned from .name() is implementation defined. But the string doesn't matter; the point is if the OP wants to determine the derived type using a base pointer, he can do: `if (typeid(*foo) == typeid(*bar)`
Charles Salvia
+3  A: 

The purpose of inheritance / polymorphism is so you don't need to care which derived type you are dealing with.

In particular I think storing data, such as make of car, country of origin etc, encoded in a class hierarchy doesn't seem to be particularly beneficial. Does an AmericanCar do something fundamentally different from, say, a Japanese car (other than consuming more fuel, which again can be better stored in a data member)?

UncleBens
+4  A: 

Well, what are you trying to do with it? Get the name or cost? You would have something like:

class Car
{
public:
    virtual ~Car(void) {}

    virtual std::string location(void) const = 0;
    virtual std::string name(void) const = 0;
    virtual double cost(void) const = 0;
}

class AmericanCar
{
public:
    virtual ~AmericanCar(void) {}

    virtual std::string location(void) const
    {
        return "America";
    }
}

class Buick : public AmericanCar
{
public:
    virtual std::string name(void) const
    {
        return "Buick";
    }

    virtual double cost(void) const
    {
        return /* ... */;
    }
}

class Ford : public AmericanCar
{
public:
    virtual std::string name(void) const
    {
        return "Ford";
    }

    virtual double cost(void) const
    {
        return /* ... */;
    }
}

Now you can call these methods polymorphically.

This is somewhat strange, though. You don't need a different class to store names and cost like this:

class Car
{
public:
    Car(const std::string& pLocation,
        const std::string& pName,
        double pCost) :
    mLocation(pLocation),
    mName(pName),
    mCost(pCost)
    {
    }

    const std::string& location(void) const
    {
        return mLocation;
    }

    void location(const std::string& pLocation)
    {
        mLocation = pLocation;
    }

    const std::string& name(void) const
    {
        return mName;
    }

    void name(const std::string& pName)
    {
        mName = pName;
    }

    const double cost(void) const
    {
        return mCost;
    }

    void cost(double pCost)
    {
        mCost = pCost;
    }

private:
    std::string mLocation;
    std::string mName;
    double mCost;
}

// make cars
std::vector<Car> cars;
cars.push_back(Car("America", "Buick", /* ... */));
GMan
A: 

Why do you need to know the derived class? Normally you would have virtual functions to take care of any behavior differences between the two derived classes.

The goal is that the code using the parent class shouldn't have to know the exact class it's working with.

ScottJ