如何调用未覆盖的派生类函数?

时间:2015-11-12 10:24:38

标签: c++ oop

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());

在没有知道哪个索引对应哪个类的情况下调用func2 的正确/干净方法是什么?做这样的事情会有约定吗?我还想避免使用 typeid

3 个答案:

答案 0 :(得分:2)

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.

答案 1 :(得分:1)

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.

答案 2 :(得分:1)

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);