通过基类虚函数获取派生类型
Get derived type via base class virtual function
我正在尝试通过基类虚函数获取对象的派生类型。我已经写了这个,它没有编译:
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;
}
。给我一个错误:我无法从base
初始化derived&
。既然get_this
是虚拟的,为什么pd->get_this()
返回base&
而不是derived&
?提前感谢!
编辑:
感谢大家的有用回答,并为我迟到的回复道歉。我应该在原始帖子中指定我也对解决我的问题感兴趣,而不仅仅是弄清楚为什么上述内容无法编译。我的主要问题是fn
是derived
类独有的,不能通过基类调用。使用强制转换确实可以解决问题,但我讨厌使用 if 其他构造编写代码只是为了获得正确的类型(斯科特迈耶斯也建议不要使用 cast:))。答案似乎表明,演员表是要走的路,这至少在某种程度上令人放心,我没有忽视一个更"优雅"的解决方案来解决我的问题。再次感谢!
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;
}
或者:
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++支持派生类的协变返回类型,但正如其他答案所描述的那样,您无法通过在此处调用基类(pd->get_this()
)来获取它。
如果您无法使用 RTTI、异常处理或想要严格的类型绑定(没有 vtable 开销),则还可以考虑静态多态性,以便在编译时检查类型合规性。
pd
的静态类型是 base *
。因此,当编译器get_this()
查找成员函数时,它只找到base::get_this()
。base::get_this()
的返回类型是 base&
,不能转换为 derived&
。因此错误。
通过参考工作C++草案的第 10.3 节第 8 段来补充 Novelocrat 的回答(单击此处),该部分解释了在这种情况下返回的指针的静态类型是 Derived* 而不是 Base*。基本上,如果您通过指向派生类的指针调用get_this()
,那么您将获得正确的类型,而不会发生编译器错误。
以下是标准的引用以及示例(也来自标准):
如果返回类型 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 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++支持协变返回类型。这意味着,当您通过base
指针在derived
对象上调用get_this()
时,将调用的是派生的实现。
但是,这并不意味着打电话给base::get_this
会给你一个derived&
。base::get_this
的返回类型为 base&
。如果你想得到一个derived
对象,你必须通过derived
指针调用get_this
(或将base&
向下投射到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&
我找到了一个简单的解决方案,但如果可能的话,我会让大师们评估:
class base{
type = 1;
virtual int getType() final {
return type;
}
}
class derived1 : public base {
derived1(){
type = 2;
}
}
这样,你可以调用任何派生类的方法'int getType()'。由于类型是在构造函数上设置的,因此不存在不当行为的风险。为了增强可用性,我创建了一个预定义的"类型"。
我正在使用,但我不知道是否是麦吉维!
- 派生类如何获取基的成员?
- 从组件的 std::type_index 获取派生最多的类型
- 通过基类指针获取派生类对象的引用
- 如何使用派生类在 c++ 中的方法之一获取派生类的名称
- 获取派生模板实例化的运行时类型
- 为什么基类型指针不能获取派生类对象的地址值?
- 当可能的许多派生类型时,从基本类型的实例中获取派生类型
- 无法获取派生类成员的值
- C++-正在获取派生类型作为模板参数
- 获取派生类访问彼此的成员数据和函数
- 通过基类虚函数获取派生类型
- 依赖于基类以获取派生类结果的C++函数
- 在C++中编译时获取派生类的类型
- 基类指针只获取派生类变量值,而不获取基类变量值的原因
- 具有基类的CRTP试图获取派生类成员的返回类型:不完整类型的使用无效
- 从 vector<Parent* 中获取派生类对象>
- 通过基指针获取派生类
- 从另一个模块获取派生类指针的接口
- 使用typeid获取派生类的名称
- 如何从 unique_ptr 向量获取派生迭代器<Base>?