简体   繁体   English

C ++继承和动态库

[英]C++ Inheritance and dynamic libraries

The idea is the following. 这个想法如下。 I have a library Version 1 with a class that looks as follows: 我有一个版本为1的类库,如下所示:

class MY_EXPORT MyClass
{
public:
    virtual void myMethod(int p1);
}

In Version 2, the class was modified to this: 在版本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);
    //...
}

Now imagine a user compiled againts Version 1 of the library, and extended MyClass by overriding myMethod . 现在,假设用户再次编译了库的版本1,并通过重写myMethod扩展了MyClass Now he updates the library to version 2, without recompiling. 现在,他将库更新为版本2, 而无需重新编译。 Let's further assume the dynamic linker still successfully finds the library and loads it. 让我们进一步假设动态链接器仍成功找到该库并加载它。

The question is, if I call the method instance->myMethod2(1, 2); 问题是,如果我调用方法instance->myMethod2(1, 2); somwhere inside the library, will it work, or will the application crash? 在库中的某个地方,它可以工作,还是应用程序崩溃? In both cases, the class has no members and thus is of the same size. 在这两种情况下,该类都没有成员,因此具有相同的大小。

I don't think there is point to guess if that app will crash or not, behavior is undefined. 我认为没有理由猜测该应用程序是否会崩溃,行为是否未定义。 The application has to be recompiled, since there was ABI change in the library. 由于库中的ABI发生了更改,因此必须重新编译该应用程序。

When library calls instance->myMethod2(1, 2); 当库调用instance->myMethod2(1, 2); it will have to go through virtual table that was created in the application code with the assumption that there is only one virtual method: myMethod . 它必须通过在应用程序代码中创建的虚拟表,并假设只有一个虚拟方法: myMethod From that point, you get undefined behavior. 从那时起,您将获得未定义的行为。 In short, you have to recompile you application when library ABI changes. 简而言之,当库ABI更改时,您必须重新编译应用程序。

KDE C++ ABI guidelines specifically prohibit such change. KDE C ++ ABI准则明确禁止此类更改。 Virtual tables of derived classes will not contain addresses for new methods and so virtual calls of those methods on objects of derived classes will crash. 派生类的虚拟表将不包含新方法的地址,因此对派生类的对象的这些方法的虚拟调用将崩溃。

By changing the definition of the class without recompiling, you've violated the One Definition Rule . 通过更改类的定义而不进行重新编译,就违反了One Definition Rule The user who did not recompile is using the old definition, while your library is using the new definition. 未重新编译的用户正在使用旧定义,而您的库正在使用新定义。 This results in undefined behavior. 这导致未定义的行为。

To see how this might manifest, consider the typical implementation of virtual functions which uses a VTable to dispatch function calls. 要了解这可能如何体现,请考虑使用VTable调度函数调用的虚拟函数的典型实现。 The library user has derived a class, and this derived class has only one function in the VTable. 库用户已派生一个类,并且此派生类在VTable中仅具有一个功能。 If a pointer or reference to this class is passed into the library, and the library tries to call the second function, it will attempt to access a VTable entry that doesn't exist. 如果将指向此类的指针或引用传递到库中,并且库尝试调用第二个函数,它将尝试访问不存在的VTable条目。 This will almost always result in a crash, although nothing is guaranteed when it comes to undefined behavior. 这几乎总是会导致崩溃,尽管对于未定义的行为,无法保证任何事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM