2

I have a library that can be compiled as a shared library (or DLL in Windows). It has a class that is derived from another class in another library. The base class has some virtual methods and my class overrides a few of them. For example:

class Base {
public:
    virtual void method1();
    virtual void method2();
    virtual void method3();
};

class Derived: public Base {
public:
    virtual void method2();
};

Now I figured out that one of the virtual methods doesn't quite work for my class. Currently it doesn't override this method, so I want to override it too to fix its behavior:

class Derived: public Base {
public:
    virtual void method2();
    virtual void method3();
};

Will this break binary compatibility with older versions of my library?

As far as I understand it, it is different from just adding virtual functions, as the number and the order of virtual methods in the vtable stays the same. The only difference is that a particular entry in the vtable for my class will now contain a different value. Is this correct?

I'm also quite sure that none of the applications currently using my library use that method, since it is completely broken and never works. So I'm not worrying about breaking existing calls to the base method implementation. I just want to make sure that I won't break anything else.

Sergei Tachenov
  • 24,345
  • 8
  • 57
  • 73
  • Logically, it sounds like it should be fine. But I'm not sure on the exact rules for maintaining binary compatibility in C++. – Mysticial Sep 08 '11 at 16:39

3 Answers3

3

Since you're talking about DLLs, I assume this is C++ in Visual Studio/Windows. Adding the override will not break binary compatibility because the size of the vtable is not changing. However, it may cause some undesired results if you don't recompile all code that instantiates new instances of Derived. This is because the vtable is initialized by the instantiating source, not the source of the class that implements Derived.

Brent M. Spell
  • 2,257
  • 22
  • 14
  • No, it's cross-platform, not just Windows, I misused the DLL term. Anyway, isn't vtable just some sort of static array of method pointers inside the DLL? And I thought that vtable pointer is initialized by the constructor. Why would the instantiating source have any effect on this process? – Sergei Tachenov Sep 08 '11 at 16:53
  • The vtable isn't just a static array, because it actually changes over the object's lifetime. Take a look at it in the debugger within the base/derived class constructor/destructor, and you'll see that the method pointers change based on whether the derived class has been constructed/destructed. – Brent M. Spell Sep 08 '11 at 18:00
  • The vtable is initialized before the constructor is called. It can't be allocated by the declaring class's module, because that class (and any classes derived from it) don't know the ultimate size of the table, since there may be new virtuals added by derivatives. So, it has to be allocated by the module that instantiates the object. – Brent M. Spell Sep 08 '11 at 18:07
  • Now, none of this behavior (or even the vtable implementation) is defined/required by the language itself, but I know that it is so on Windows/VC++. – Brent M. Spell Sep 08 '11 at 18:13
  • The vtable pointer (the field in a class instance) changes during initialization, right, but it happens as each constructor called. My constructor isn't inline so it's located in the DLL, although called from the application. The vtable itself (the thing that the vtable pointer points to) is fixed for every class in the hierarchy and is known at compile time, so it should be initialized at compile time and adjusted at startup during relocation process. So both vtable and vtable pointer are initialized in the DLL. Where am I wrong? – Sergei Tachenov Sep 08 '11 at 18:29
  • On Windows, at least, the contents of the vtable is not stored within the object's module and then referenced by the code instantiating the object. Consider an example where you have only the header file for a class (no inline methods) and the associated DLL and the associated lib. The lib will include only the stubs for the methods of the class (no data members, including the vtable). So, the VC compiler must create a vtable in the instantiating module for the class as it sees it. Obviously, this could be implemented differently on other platforms, but it is not so in Windows. – Brent M. Spell Sep 08 '11 at 18:43
  • By Windows, you mean VC? Right now, I am testing this on Windows/MinGW, so I guess things could be different here. As for VC, with the process you've described, the only undesirable effect would be that old applications will still be calling the base class implementation, right? – Sergei Tachenov Sep 08 '11 at 19:08
0

If I understood correctly you have your Base class in Dll1 and your Derived class in Dll2. If this is the case the change you describe doesn't affect Dll1. Assuming you'll install an updated Dll2 your application will switch to call Derived::method3() whenever you access instances of Derived through pointers or references to Base.

Nicola Musatti
  • 17,834
  • 2
  • 46
  • 55
0

The library your derived class (that added the new virtual method) exists in will not necessarily be binary (ABI) compatible with the old version of the library. This is because you have no control over how the vtable is generated by the compiler when you add the overridden virtual method.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • But I thought that any compiler has to generate a vtable that is compatible with that of the base class? And that vtable stays the same, I don't (and can't) change it. – Sergei Tachenov Sep 08 '11 at 16:55