通过基 class 函数指针调用派生 class
Calling derived class through base class function pointer
我可以通过基 class 函数 pointer 调用派生的 class 吗?
我知道我的示例 有效 ,但是否保证始终如此(假设对象实际实现了该功能!),或者这只是编译器的特性我在用?
按照这种逻辑,不能简单地从 "CBase" 中导出所有 classes(在本例中是空的,所以我猜没有开销)并忽略函数指针中的类型吗?
#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;
}
示例使用场景:
派生的 class 接受一个或多个指向基 class 中的 "callbacks" 的指针。是否可以仅使用派生的 class 定义回调类型,从而放弃对模板的需求?
您可以使用此方法,但转换指针根本不是一个好的做法。您使用的方法与多态性没有共同之处。更好的实现方法是使用 virtual
函数和 pure
函数。
你的基础 class 必须有一个纯函数(纯函数也是虚拟的)并且你的派生 class 必须实现这个函数。因此,您将能够使用基指针调用此函数,并调用派生 class 的实现。
#include "stdafx.h"
#include <iostream>
struct CBase
{
virtual void MyFunction() =0; // this is a `pure` function. Pure means it's a virtual and may not have implementation. If a class has at least one pure function it means this class is an abstract class
virtual ~CBase()=default; // gotta be or we will have a memory leak during `delete`..
};
struct CDerived : CBase
{
virtual void MyFunction() override
{
std::cout << "Called OK" << std::endl;
}
};
//typedef void (CBase::*FunctionPointer)();
int main()
{
CBase* base = new CDerived();
base->MyFunction();
delete base;
system("pause");
return 0;
}
是的,保证有效。来自 [expr.static.cast]:
A prvalue of type “pointer to member of D
of type cv1 T
” can be converted to a prvalue of type “pointer
to member of B
of type cv2 T
”, where B
is a base class (Clause 10) of D
, 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 class B
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
成员的指针转换为指向类型 void()
的 CBase
成员的指针。 CBase
是包含原始成员的 class 的基础,因此生成的指针指向原始成员。
来自[expr.mptr.oper]:
Abbreviating pm-expression.*cast-expression as E1.*E2
, E1
is called the object expression. If the dynamic
type of E1
does not contain the member to which E2
refers, the behavior is undefined.
在这种情况下,pointer
指向原始成员。 base
有那个成员。所以这很好。
请注意,在您的示例中,base
实际上是 CDerived*
。写成同样有效:
CDerived d;
CBase* b = &d;
(b->*pointer)(); // ok - the dynamic type of b contains the member to which pointer refers
我可以通过基 class 函数 pointer 调用派生的 class 吗?
我知道我的示例 有效 ,但是否保证始终如此(假设对象实际实现了该功能!),或者这只是编译器的特性我在用?
按照这种逻辑,不能简单地从 "CBase" 中导出所有 classes(在本例中是空的,所以我猜没有开销)并忽略函数指针中的类型吗?
#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;
}
示例使用场景: 派生的 class 接受一个或多个指向基 class 中的 "callbacks" 的指针。是否可以仅使用派生的 class 定义回调类型,从而放弃对模板的需求?
您可以使用此方法,但转换指针根本不是一个好的做法。您使用的方法与多态性没有共同之处。更好的实现方法是使用 virtual
函数和 pure
函数。
你的基础 class 必须有一个纯函数(纯函数也是虚拟的)并且你的派生 class 必须实现这个函数。因此,您将能够使用基指针调用此函数,并调用派生 class 的实现。
#include "stdafx.h"
#include <iostream>
struct CBase
{
virtual void MyFunction() =0; // this is a `pure` function. Pure means it's a virtual and may not have implementation. If a class has at least one pure function it means this class is an abstract class
virtual ~CBase()=default; // gotta be or we will have a memory leak during `delete`..
};
struct CDerived : CBase
{
virtual void MyFunction() override
{
std::cout << "Called OK" << std::endl;
}
};
//typedef void (CBase::*FunctionPointer)();
int main()
{
CBase* base = new CDerived();
base->MyFunction();
delete base;
system("pause");
return 0;
}
是的,保证有效。来自 [expr.static.cast]:
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
成员的指针转换为指向类型 void()
的 CBase
成员的指针。 CBase
是包含原始成员的 class 的基础,因此生成的指针指向原始成员。
来自[expr.mptr.oper]:
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
有那个成员。所以这很好。
请注意,在您的示例中,base
实际上是 CDerived*
。写成同样有效:
CDerived d;
CBase* b = &d;
(b->*pointer)(); // ok - the dynamic type of b contains the member to which pointer refers