mkmostafa
mkmostafa

Reputation: 3171

How to invoke a call to a not overridden derived class function?

class Base {
virtual void func1();
}

class Derived : Base {
void func1();
void func2();
}

vector<Base *> vec;
vec.push_back(new Base()), vec.push_back(new Derived());

What is the correct/clean way to call func2 without knowing which index corresponds to which class? Is there a convention to do such a thing? I also want to avoid using typeid.

Upvotes: 0

Views: 81

Answers (3)

king_nak
king_nak

Reputation: 11513

If you don't want to use RTTI at all (including dynamic_cast), you could simulate its behaviour like Qt does it with qgraphicsitem_cast

Outline:

class Base {
public:
    enum { Type = 0 };
    virtual int type() { return Type; }
};
class Derived : public Base {
public:
    enum { Type = 1 };
    int type() { return Type; }
};

template<typename T>
inline T myobject_cast(Base *b) {
    if (b) {
       // Requires C++11
       if (int(std::remove_pointer<T>::type::Type) == b->type()) {
          return static_cast<T>(b);
       }
       /* Pre C++11 (might be UB, but works on many compilers, OpenSource and Commercial)
       if (int(static_cast<T>(0)->Type) == b->type()) {
          return static_cast<T>(b);
       }
       */
    }
    return NULL;
}

// use:
Base *b = new Base;
Base *d = new Derived;
Derived *o1 = myobject_cast<Derived*> (b); // NULL
Derived *o2 = myobject_cast<Derived*> (d); // d

Each class would require a unique Type member for this to work.

Be aware that this will not work with "intermediate" classes in the hierarchy. Only the actual, most derived type will can be cast to (e.g. a DerivedDerived cannot be cast to a Derived, or Base for that matter).

You might also find an overload for const handy:

template<typename T> inline T myobject_cast(const Base *b)
{ return (b && int(static_cast<T>(0)->Type) == b->type()) ? static_cast<T>(p) : 0; }

const Base *cb = new Derived;
const Derived *co = myobject_cast<const Derived *>(cb);

Upvotes: 1

user4578093
user4578093

Reputation: 229

This function will take one of said pointers and call func2 if possible, and simply return false otherwise

bool CallFunc2(Base* Bae){
  Derived* Der;
  if (Der = dynamic_cast<Derived*>(Bae))
    {Der->func2(); return true;}
  else
    return false;
}

This works on the principle that dynamic_cast returns a null pointer if the object being cast cannot be converted.

Upvotes: 1

alexeykuzmin0
alexeykuzmin0

Reputation: 6440

In your case the objects are sliced, as mentioned in king_nak's answer, so there's no safe way to call func2().
But you can store pointers to Base instead of Base objects - in this case you can use dynamic_cast:

std::vector<Base*> vec;
vec.push_back(new Base());
vec.push_back(new Derived());

for (auto obj : vec)
{
    Derived* d = dynamic_cast<Derived*>(obj);
    if (d)
    {
        d->func2();
    }
}

Some info on dynamic_cast: link

PS: Also, if you want to call function func2() on Base objects, I think it makes sense to add a stupid implementation to Base class and make the function virtual.

Upvotes: 2

Related Questions