Search code examples
c++binary-compatibility

why new virtual function will not break binary compatibility per phenomenon?


I'm learning the binary compatibility based on this KDE wiki, and see that

add a virtual function to a class that doesn't have any virtual functions or virtual bases

will break compatibility. Then I had a try.

Assume I want to create a FastString.dll to provide out, and here is the definition.

//FastString.h

#ifdef _DLL_EXPORT
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT __declspec(dllimport)
#endif

class LIB_EXPORT FastString
{
public:
    FastString(void);
    ~FastString(void);

    int length();

private:
    int m_len;
    unsigned char *m_bytes;
};

and implementation

//FastString.cpp
#include "FastString.h"

FastString::FastString(void)
{
    m_len = 0;
}

FastString::~FastString(void)
{
}

int FastString::length()
{
    printf("Function of length, string len is %d\n", m_len);
    return m_len;
}

While in the third exe file test.exe, used FastString like below

// main.cpp

#include <conio.h>
#include "FastString.h"

int _tmain(int argc, _TCHAR* argv[])
{
    FastString str;
    str.length();

    printf("Please input any key to exit...");
    _getch();
    return 0;
}

Please note: in main.cpp the included FastString.h is another file, when I added the virtual function in FastString, the modification is under FastString.dll.

They are in the same solution (compiler: VS2012), and build successfully. After that, I add a new virtual function in FastString.h.

virtual bool isEmpty();

And in FastString.cpp, I implement it with simple return

bool FastString::isEmpty()
{
    return false;
}

Then I build the FastString.dll individually, and rerun test.exe. The output is same with previous one without any error.
So, why this behavior is not broken the binary compatibility?
Per my understanding, the instance str should have a vtable pointer, and the memory layout must has been changed.
I also had a debug based on VS tool and found the str still had no _vptr, does it mean the vtable is created under compiler period, not in link period?


Solution

  • The calling of the non-virtual function FastString::length() is layout independent and that function being defined in the DLL knows the actual object layout and finds the right member. You should be hit by layout incompatibilities by making m_len public and accessing it from outside of DLL.

    While there is no general rule about where the VMT is located it is usually created by compiler and put inside some specific translation unit (*.obj) , i.e. there where the first virtual function is defined. Sometimes when for instance all virtual functions are inline more advanced strategies must be applied and they usually involve linker. But generally when using an older header compiler will have not enough hints involving presence of the VMT and will not create a VMT pointer for that object.