C++ 通过基类虚函数获取派生类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19501838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:54:55  来源:igfitidea点击:

Get derived type via base class virtual function

c++typesderived

提问by linuxfever

I am trying to get the derived type of an object via a base class virtual function. I have written this, which does not compile:

我试图通过基类虚函数获取对象的派生类型。我写了这个,它不能编译:

struct base {
  virtual base& get_this() {
    return *this;
  }
};

struct derived : base {
  virtual derived& get_this() override {
    return *this;
  }

  void fn();
};


int main () {
  base* pd = new derived();
  derived& x = pd->get_this(); /*ERROR*/
  x.fn();
  return 0;
}

... giving me an error that: I cannot initialize a derived&from a base. Since get_thisis virtual, why does pd->get_this()return a base&instead of a derived&? Thanks in advance!

...给我一个错误:我无法derived&从 a初始化a base。既然get_this是虚拟的,为什么pd->get_this()返回 abase&而不是 a derived&?提前致谢!

EDIT:

编辑:

Thanks everyone for their useful answers and apologies for my late reply. I should have specified in the original post that I am also interested in a solution to my problem rather than just figuring out why the above does not compile. My main problem is that fnis unique to the derivedclass and cannot be called via the base class. Using casts sure solves the problem but I hate writing code with if else constructs just to get the right type (also Scott Meyers advise against casts :)) . The answers seem to indicate that casts are the way to go, which in a way is at least reassuring that I am not neglecting a more 'elegant' solution to my problem. Thanks again!

感谢大家的有用答案,并为我迟到的回复道歉。我应该在原始帖子中指定我也对解决我的问题感兴趣,而不仅仅是弄清楚为什么上述内容无法编译。我的主要问题是该类fn是唯一的,derived不能通过基类调用。使用强制转换确实可以解决问题,但我讨厌使用 if else 构造编写代码只是为了获得正确的类型(Scott Meyers 也建议不要使用强制转换:))。答案似乎表明演员表是要走的路,这在某种程度上至少令人放心,我没有忽视对我的问题的更“优雅”的解决方案。再次感谢!

采纳答案by π?ντα ?ε?

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

C++ 协变返回类型支持只会起作用,只要您已经知道派生类型。要将基类向下转换为可能的派生类,只需使用dynamic_cast<derived>(base_ref)确定 base_ref 是否与实际派生类型匹配:

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

c++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.

c++支持派生类的协变返回类型,但正如其他答案所描述的那样,您无法通过在pd->get_this()此处调用基类 ( ) 来获得它。

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

如果您不能使用RTTI、异常处理或想要紧密的类型绑定(没有 vtable 开销),您也可以考虑使用静态多态来在编译时检查类型合规性。

回答by Phil Miller

The static type of pdis 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.

的静态类型pdbase *。因此,当编译器查找成员函数 时get_this(),它只找到base::get_this(). 的返回类型base::get_this()base&,不能转换为derived&。因此错误。

回答by Phil Miller

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.

我想通过向您介绍C++ 标准工作草案(单击此处)的第 10.3 节第 8 段来添加 Novelocrat 的答案,它解释了在这种情况下返回的指针的静态类型是 Derived*,而不是 Base*。基本上,如果您get_this()通过指向派生类的指针进行调用,那么您将获得正确的类型,而不会出现编译器错误。

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

这是标准的引用以及示例(也来自标准):

If the return type of D::f di?ers 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 ?nal overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2). [Example:

如果 D::f 的返回类型与 B::f 的返回类型不同,则 D::f 的返回类型中的类类型应在 D::f 的声明点完成或应为类类型 D。当覆盖函数被调用作为被覆盖函数的最终覆盖时,其结果被转换为(静态选择的)被覆盖函数返回的类型(5.2.2)。[例子:

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 di?erence 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
}

回答by log0

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

C++ 支持协变返回类型。它的意思是,当你调用get_this()一个上derived通过对象base的指针是推导出将被称为实施。

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

然而,这并不意味着调用base::get_this会给你一个derived&. 的返回类型base::get_thisbase&。如果你想得到一个derived对象,你将不得不get_this通过一个derived指针调用(或向下转换你base&的 a derived&)。请注意,这就是返回类型协方差在 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&

回答by Auradrummer

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'.

这样,您可以调用任何派生类的方法“int getType()”。由于类型是在构造函数上设置的,因此不存在行为不当的风险。为了提高可用性,我创建了一个预定义的“类型”。

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

我在用,不知道是不是MacGyvery!