通过基类函数指针调用派生类 [英] Calling derived class through base class function pointer
问题描述
是否可以通过基类函数 pointer 调用派生类,如下面的示例所示?
Can I call a derived class through a base class function pointer, as shown in the example below?
我知道我的示例可以工作,但是可以保证总是这样做(假设对象实际上实现了该功能!),或者这仅仅是我使用的编译器的特质?
I understand that my example works, but is it guaranteed to always do so (Assuming the object actually implements the function!), or is this just an idiosyncrasy of the compiler I'm using?
通过这种逻辑,不能简单地从"CBase"(在这种情况下为空,因此我认为没有开销)派生所有类并忽略函数指针中的类型吗?
By this logic can't one simply derive all their classes from "CBase" (which in this case is empty so I guess no overhead) and ignore the type in the function pointer?
#include <iostream>
struct CBase
{
};
struct CDerived : CBase
{
void MyFunction()
{
std::cout << "Called OK" << std::endl;
}
};
typedef void (CBase::*FunctionPointer)();
int main()
{
CDerived* base = new CDerived();
FunctionPointer pointer = static_cast<FunctionPointer>(&CDerived::MyFunction);
(base->*pointer)();
delete base;
}
使用场景示例: 一个派生类,它在基类中采用一个或多个指向回调"的指针.可以仅使用派生类定义回调类型,从而放弃对模板的需求吗?
Example usage scenario: A derived class that takes one or more pointers to "callbacks" in the base class. Can the callback type just be defined using the derived class and thus forgo the need for a template?
推荐答案
是的,保证可以正常工作.来自[expr.static.cast]:
Yes, it's guaranteed to work. From [expr.static.cast]:
指向 cv1
T
类型的D
的成员的指针"的prvalue可以转换为"pointer类型"的prvalue 到 cv2T
类型的B
成员,如果 cv2 相同,则B
是D
的基类(第10条) cv -资格 作为或大于cv1.70的cv资格如果没有从指针到B的成员"的有效标准转换 如果存在类型T"到指向类型T的D的成员的指针"(4.11),则程序格式不正确.空成员 指针值(4.11)转换为目标类型的空成员指针值.如果类B
包含 原始成员,或者是包含原始成员的类的基类或派生类,其结果 指向成员的指针指向原始成员.
A prvalue of type "pointer to member of
D
of type cv1T
" can be converted to a prvalue of type "pointer to member ofB
of type cv2T
", whereB
is a base class (Clause 10) ofD
, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.70 If no valid standard conversion from "pointer to member of B of type T" to "pointer to member of D of type T" exists (4.11), the program is ill-formed. The null member pointer value (4.11) is converted to the null member pointer value of the destination type. If classB
contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member.
在这种情况下,我们将指向void()
类型的CDerived
成员的指针转换为CBase
ov类型的void()
成员的指针. CBase
是包含原始成员的类的基础,因此生成的指针指向原始成员.
In this case, we're converting a pointer to member of CDerived
of type void()
to a poitner to member of CBase
ov type void()
. CBase
is a base of the class containing the original member, so the resulting pointer points to the original member.
来自[expr.mptr.oper]:
From [expr.mptr.oper]:
将pm-expression.* cast-expression缩写为
E1.*E2
,E1
被称为对象表达式.如果动态E1
的类型不包含E2
所引用的成员,其行为是不确定的.
Abbreviating pm-expression.*cast-expression as
E1.*E2
,E1
is called the object expression. If the dynamic type ofE1
does not contain the member to whichE2
refers, the behavior is undefined.
在这种情况下,pointer
指向原始成员的指针. base
具有该成员.所以这很好.
In this case, pointer
pointers to the original member. base
has that member. So this is fine.
请注意,在您的示例中,base
实际上是一个CDerived*
.写作同样有效:
Note that in your example, base
is actually a CDerived*
. It would be just as valid to write:
CDerived d;
CBase* b = &d;
(b->*pointer)(); // ok - the dynamic type of b contains the member to which pointer refers
这篇关于通过基类函数指针调用派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!