2
votes
class Base
{
protected:
    string m_Name;
public:
    virtual string Name() { return m_Name; }
    virtual string Type() = 0;
    virtual bool isEqual(Base* rhs) = 0 ;
};

I have an abstract class Base. Different class in my code inherit from this Base class. I store these object in a container (a vector of pointer of Base)

struct Container
{
    vector<Base*> vec;
    int Count() { return vec.size(); }
    Base* operator[](int i)
    {
        if (i<=0) throw anexception;
        if (i>=vec.size()) throw anexception;
        return vec[i];
    }
};

I overloaded the operator [], but I only manage to return a pointer. Is there a way so that I can return the object vec[i] (which is of a type that inherit from Base)?

3

3 Answers

3
votes

You can simply return a reference if you wish to return the object pointed to by vec[i]:

Base& operator[](int i)
{
    if (i<=0) throw anexception;
    if (i>=vec.size()) throw anexception;
    return *vec[i];
}

However, you cannot return a copy of the object without knowing the derived type, since that would require constructing a new Base from your old object - and that is not possible since Base is abstract.

0
votes

You should not.

Returning an instance of a class means you need to invoke copy or move constructor. If you did that, then you'd invoke a copy constructor of a base class. Since base class has no knowledge of derived classes, the returned copy will be a sliced version of your derived class.

This means that if derived classes have variables that are not present in the base class, they will be left out. Not to mention that virtual functions will be those of the base class.

You could return a reference, but I don't see how it would be better than returning a pointer. You'd certainly be exposed to slicing, if you use the reference carelessly.

0
votes

You can write a function where you specify the desired type:

struct Container
{
    ...
    template<typename T>
    T* at(int i)
    {
        ...
        return dynamic_cast<T*>(vec[i]);
    }
};

Container c;
Derived1* d = c.at<Derived1>(3);

This will return a valid pointer if the object is indeed of the specified type and a null pointer otherwise.

You can not do this with operator[] however.


In general, the type of an polymorphic object accessed via a pointer to a base class is not known at runtime. The only way to get from the base class to the typed derived class is by using a form of switch statement which handles all possible derived classes:

Base* p = ...;
if(dynamic_cast<Derived1*>(p)) { ... }
else if(dynamic_cast<Derived2*>(p)) { ... }
else if(dynamic_cast<Derived3*>(p)) { ... }
else { ERROR }

This is of course something you would want to avoid.