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

lin*_*ver 9 c++ types derived

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

πάν*_*ῥεῖ 8

只有你已经知道派生类型,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;
}
Run Code Online (Sandbox Code Playgroud)

或者:

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;
}
Run Code Online (Sandbox Code Playgroud)

支持派生类的协变返回类型,但正如其他答案描述的那样,你无法通过调用基类(pd->get_this())来获取它.

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