在工作的过程中,发现了一个C++中有趣的问题。
我有一个zemotion.dll的动态库文件,且该动态库文件中有一个名为setXYPosition的函数,且在.pro文件中被正确导入。
我的工程文件中,有一个zeadapter.h的头文件(但没有对应的zeadapter.cpp源文件),还有一组zescope.h和zescope.cpp的头文件和源文件。
此时,这两组头文件下,都定义了与动态库文件中的setXYPosition,同样名字和输入的setXYPosition函数。
在zeadapter.h中,声明为:
//虽为虚函数,但未被覆盖
virtual void setXYPosition(double x, double y) throw (DeepSightError) = 0;
在zescope.h中,声明为:
public:
void setXYPosition(double x, double y) throw (DeepSightError);
private:
//此头文件下还持有zeadapter.h的指针
zeadapter* zead = nullptr;
在zescope.cpp中,实现为:
void zescope::setXYPosition(double x, double y) throw (DeepSightError)
{
if (isAdapterInstallSuccessed()) {
zead->setXYPosition(x, y);
} else {
::setXYPosition(x, y);
}
}
困扰我的地方在于,那么多同名的函数,到底谁才是真正调用zemotion.dll动态库中的setXYPosition函数的代码。
此问题涉及到了多态和动态库函数调用的问题,基于这个问题,我们做出以下分析:
①当一个 h头文件没有对应的 cpp源文件,但是其声明了 zemotion.dll 动态库中的 setXYPosition 函数时;或者一个 h头文件有对应的 cpp源文件,但仅在 h头文件中声明了 zemotion.dll 动态库中的 setXYPosition 函数,但 cpp源文件中并无此函数的实际实现时。若在其他文件中调用此头文件下的 setXYPosition 函数,则程序实际上调用的就是 zemotion.dll 动态库中的 setXYPosition 函数。
②当一个 h头文件有对应的 cpp源文件,且 h头文件中声明了与 zemotion.dll 动态库文件中的 setXYPosition 函数的同名函数,且对应的 cpp源文件中同样有 setXYPosition 函数的具体实现。则其他文件在调用此头文件下的 setXYPosition 函数时,程序实际上只会调用此 h头文件对应的cpp源文件下的 setXYPosition 函数,而不会调用动态库中的 setXYPosition 函数。
③但如果在②条件下,在 cpp源文件中的 setXYPosition 函数下又写了一个 ::setXYPosition,则此时若程序运行到此处时,程序实际上调用的会是 zemotion.dll 动态库文件中的 setXYPosition 函数!!!但如果写的是 setXYPosition ,而不是 ::setXYPosition,则此时程序进入递归。
④如果在①条件下,有新的 h头文件覆盖了 zeadapter.h 中的 setXYPosition 虚函数,并且在对应的 cpp源文件中有具体的 setXYPosition 函数的实现,则程序在进入 zead->setXYPosition(x, y);时,将实际执行派生类的具体实现,而非动态库中的 setXYPosition 函数。
总结:
若 一个头文件声明了动态库的同名函数但没有cpp文件或者派生类的具体实现,则其他文件调用该头文件下的此函数时,将实际调用动态库中的同名函数。
若 一个头文件和源文件,分别声明和具体实现了动态库中的同名函数,则程序实际将不会调用动态库中的同名函数,只会调用对应源文件的具体实现(因为链接器优先解析本地符号)。
若 具体实现中,使用了带有区分的 :: 符号,后接动态库中的同名函数,则程序运行到此行时实际将会调用动态库的同名函数。