Chr*_*son 33 c++ virtual-functions
简而言之:从指向派生类实例的C++基类指针,如何在运行时确定是否已重新实现非纯虚函数(在基类中具有实现)派生类?
上下文:
我正在编写一个C++库来解决某些类别的数学方程.该库提供了一个Equation具有多个虚函数的类,库用户将其用作他们希望解决的特定等式的基类.该库还提供了一个Solver类,它接受Equation *一个构造函数参数.然后用户按以下方式编写代码:
class MyEquation : public Equation
{ ... } // equation definition here
int main()
{
MyEquation myEqn;
Solver solver(&myEqn);
solver.Solve();
}
Run Code Online (Sandbox Code Playgroud)
如果虚拟函数的某些组合Equation未在导出的方程类中重新定义,Solver则可以省略由对象运行的算法的某些计算上昂贵的部分.因此,我想知道,在构造函数中Solver,哪些函数已被重新定义,而是将运行默认实现Equation.
我想让这对图书馆的用户透明,所以我不是在寻找一个解决方案,例如,用户在派生方程的构造函数中设置一些标志,指定哪些函数已被重新定义.
一种可能的解决方案是在虚拟函数的默认实现中Equation设置类中的私有标志Equation; Solver然后,类的构造函数可以清除此标志,运行虚函数,并检查标志值以查看是否Equation已调用实现.我想避免这种情况,因为每次执行虚函数时只需设置标志就会使算法减慢很多(这些虚函数的执行对程序的运行时间有很大帮助,而默认实现只返回一个常数).
Che*_*Alf 19
您无法移植地检查虚拟功能的覆盖.
您需要将知识带到Solver,最好是通过类型而不是运行时标志.
一种(基于类型)方式是通过检查接口的存在或不存在dynamic_cast.
一种可能更好的方法是提供solve函数的重载,在你的情况下是Solver构造函数.
如果您提供更具体的问题描述,可能会给出更好的建议.它确实提醒了某人(1)需要解决某些问题P的典型情况,(2)设想技术方法X作为P的解决方案,(3)发现X不削减它,(4)询问如何使X适用于P的模糊描述,甚至是一些不相关的问题Q.原始问题P的细节通常会提出比X更好的解决方案,以及使X工作的问题,与解决P.无关.
Joh*_*ith 12
为了将来参考,结果是GCC提供了这个扩展:http://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html,它允许检查方法是否被覆盖
(void*)(obj.*(&Interface::method)) != (void*)(&Interface::method)
Run Code Online (Sandbox Code Playgroud)
ICC正式支持此扩展,clang的文档没有提及它,但代码工作,甚至编译没有警告.
但是,MSVC并不支持这一点,所以就是这样.
此外,如果您链接到实现已更改的库的不同版本,它似乎无法使用单独库中的标头(即内联)中定义的方法.如果我正确地解释了标准,这是未定义的行为(改变实现),但如果实现保持不变,那么地址也应该是唯一的.所以不要使用内联方法.
在找到链接到gcc的PMF扩展名的结果后,我认为必须有一个正确的方法.
我找到了一个没有任何黑客攻击的解决方案,至少经过测试可以在gcc&llvm上工作:
#include <iostream>
#include <typeinfo>
struct A { virtual void Foo() {} };
struct B : public A { void Foo() {} };
struct C : public A { };
int main() {
std::cout << int(typeid(&A::Foo) == typeid(&A::Foo)) << std::endl;
std::cout << int(typeid(&A::Foo) == typeid(&B::Foo)) << std::endl;
std::cout << int(typeid(&A::Foo) == typeid(&C::Foo)) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
PS:我实际上是在CEventClient系统中使用它.因此,您从CEventClient派生您的类,如果它覆盖了一个事件方法,它将自动"链接"该事件.