Get derived type via base class virtual function

半城伤御伤魂 提交于 2019-11-30 19:06:24
πάντα ῥεῖ

C++ covariant return types support will only work, as long you already know the derived type. To downcast a base class to a possibly derived class, simply use dynamic_cast<derived>(base_ref) to determine if base_ref matches the actual derived type:

int main () {
    base* pd = new derived();
    derived& x = dynamic_cast<derived&>(*pd); // Will throw an exception if pd 
                                          // isn't a 'derived'
    x.fn();
    return 0;
}

Or alternatively:

int main () {
    base* pd = new derived();
    derived* x = dynamic_cast<derived*>(pd); // Will return nullptr if pd isn't
                                         // a 'derived'
    if(x) {
        x->fn();
    }
    else {
        // dynamic_cast<derived*> failed ...
    }
    return 0;
}

supports covariant return types for derived classes, but as the other answers describe you cannot get it via calling the base class (pd->get_this()) here.

You might also consider static polymorphism to check type compliance at compile time, if you can't use RTTI, exception handling or want tight type binding (without vtable overhead).

The static type of pd is base *. Thus, when the compiler looks for the member function get_this(), it finds only base::get_this(). The return type of base::get_this() is base&, which is not convertible to derived&. Hence the error.

I would like to add to Novelocrat's answer by referring you to section 10.3, paragraph 8 of the working draft C++ standard (click here) which explains in which case the returned pointer's static type is Derived* as opposed to Base*. Basically, if you would have called get_this() through a pointer to the dervied class then you would have gotten the right type with no compiler error.

Here is a quote from the standard along with an example (also from the standard):

If the return type of D::f differs from the return type of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D. When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2). [Example:

class B { };
class D : private B { friend class Derived; };
struct Base {
    virtual void vf1();
    virtual void vf2();
    virtual void vf3();
    virtual B* vf4();
    virtual B* vf5();
    void f();
};

struct No_good : public Base {
    D* vf4(); // error: B (base class of D) inaccessible
};

class A;
struct Derived : public Base {
    void vf1(); // virtual and overrides Base::vf1()
    void vf2(int); // not virtual, hides Base::vf2()
    char vf3(); // error: invalid difference in return type only
    D* vf4(); // OK: returns pointer to derived class
    A* vf5(); // error: returns pointer to incomplete class
    void f();
};

void g() {
    Derived d;
    Base* bp = &d; // standard conversion:
    // Derived* to Base*
    bp->vf1(); // calls Derived::vf1()
    bp->vf2(); // calls Base::vf2()
    bp->f(); // calls Base::f() (not virtual)
    B* p = bp->vf4(); // calls Derived::pf() and converts the
    // result to B*
    Derived* dp = &d;
    D* q = dp->vf4(); // calls Derived::pf() and does not
    // convert the result to B*
    dp->vf2(); // ill-formed: argument mismatch
}

C++ supports covariant return type. What it means is that when you call get_this() on a derived object through a base pointer it is the implementation of derived that is going to be called.

However this does not mean that calling base::get_this will give you a derived&. The return type of base::get_this is base&. if you want to get a derived object you will have to call get_this through a derived pointer (or downcast your base& to a derived&). Note that this is how return type covariance work in Java, C++, D...

base* pbase = new base();
base* pderived = new derived();
derived* pderived2 = new derived();

base& a = pbase->get_this();        // call implementation in base, return base&
base& b = pderived->get_this();     // call implementation in derived, return base&
derived& c = pderived2->get_this(); // call implementation in derived, return derived&

I found a simple solution, but if is possible, I would the masters to evaluate:

class base{ 
    type = 1;
    virtual int getType() final {
        return type;
    }
}

class derived1 : public base {
    derived1(){
        type = 2;
    }
}

This way, you can call the method 'int getType()' of any of derived classes. As the type is set on the constructor, there is no risk of misbehaviour. To enhance the usability, i've created a predefined 'types'.

I'm using, but I don't know if is MacGyvery!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!