[英]C++ Inheritance and dynamic libraries
这个想法如下。 我有一个版本为1的类库,如下所示:
class MY_EXPORT MyClass
{
public:
virtual void myMethod(int p1);
}
在版本2中,将该类修改为:
class MY_EXPORT MyClass
{
public:
virtual void myMethod(int p1);
virtual void myMethod2(int p1, int p2);
}
//implementation of myMethod2 in cpp file
void MyClass::myMethod2(int p1, int p2)
{
myMethod(p1);
//...
}
现在,假设用户再次编译了库的版本1,并通过重写myMethod
扩展了MyClass
。 现在,他将库更新为版本2, 而无需重新编译。 让我们进一步假设动态链接器仍成功找到该库并加载它。
问题是,如果我调用方法instance->myMethod2(1, 2);
在库中的某个地方,它可以工作,还是应用程序崩溃? 在这两种情况下,该类都没有成员,因此具有相同的大小。
我认为没有理由猜测该应用程序是否会崩溃,行为是否未定义。 由于库中的ABI发生了更改,因此必须重新编译该应用程序。
当库调用instance->myMethod2(1, 2);
它必须通过在应用程序代码中创建的虚拟表,并假设只有一个虚拟方法: myMethod
。 从那时起,您将获得未定义的行为。 简而言之,当库ABI更改时,您必须重新编译应用程序。
KDE C ++ ABI准则明确禁止此类更改。 派生类的虚拟表将不包含新方法的地址,因此对派生类的对象的这些方法的虚拟调用将崩溃。
通过更改类的定义而不进行重新编译,就违反了One Definition Rule 。 未重新编译的用户正在使用旧定义,而您的库正在使用新定义。 这导致未定义的行为。
要了解这可能如何体现,请考虑使用VTable调度函数调用的虚拟函数的典型实现。 库用户已派生一个类,并且此派生类在VTable中仅具有一个功能。 如果将指向此类的指针或引用传递到库中,并且库尝试调用第二个函数,它将尝试访问不存在的VTable条目。 这几乎总是会导致崩溃,尽管对于未定义的行为,无法保证任何事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.