Change pure virtual to virtual and stay binary compatible
Asked Answered
S

2

8

Can I change a pure-virtual function (in a base class) to become non-pure without running into any binary compatibility issues? (Linux, GCC 4.1)

thanks

Sawmill answered 19/7, 2011 at 14:33 Comment(0)
I
3

What does it mean to maintain binary compatibility to you?

The object layout will be the same, but you will be breaking the One Definition Rule unless you recompile all code, at which point binary compatibility is basically useless. Without recompiling, then the ODR is broken, and while it might be the case that it works, it might also not work.

In particular if all of the virtual methods in the class are either pure or defined inline, then the compiler might generate the vtable in each translation unit that includes the header and mark it as a weak symbol. Then the linker will pick one of them and discard all the others. In this situation the linker is not required to verify that all of the vtables are exactly the same and will pick one at random (or deterministically in an undefined way), and it might pick one such vtable where the method is pure virtual, which in turn might end up crashing the application if the method is called on an object of the base class.

Ison answered 19/7, 2011 at 16:31 Comment(2)
In my case not all the virtual methods are pure, there's a mixture. I guess I'll rebuild everything anyway though, rather than live with the uncertainty.Sawmill
Specifically I had N shared libraries. I'm only calling the virtual function via a base class pointer in the first lib; the other N-1 libs contain derived classes with re-implementations of that function. I'd planned to change the pure to a non-pure and recompile the first library only.Sawmill
C
4

There is no compatibility issues when you switch from pure virtual to virtual and then re-compile the code. (However, virtual to pure virtual may cause problems.)

The only thing you should take care is, that the non-pure virtual methods must have a body. They cannot remain unimplemented. i.e.

class A {
public:
  virtual int foo ()
  {
    return 0; //put some content
  }
};

You cannot simply put like,

virtual int foo();

It will cause linker error, even if you don't use it.

Confiscate answered 19/7, 2011 at 14:36 Comment(4)
This is not really safe, this is a violation of the ODR (different translation units have different definitions for the same type) and might cause problems under some circumstances.Uranography
@David, can you give example ?Confiscate
I think I provided on in the answer I gave, but I will try to simplify. If all of the virtual methods are either pure virtual or defined inlined in the class definition, then there is no single translation unit that creates the vtable, but rather all translations that include that header. The vtable will be marked as a weak symbol and the linker will randomly choose one of them. If you have code that depends on the base class being instantiable that calls the (not pure for this translation unit) virtual function, and the linker has chosen a vtable where that function is pure...Uranography
... then the code will call what (according to the vtable) is a pure virtual function, and that is usually handled by a thunk that prints a message and terminates the application. The problem with ODR violations is that they don't need to be diagnosed, and in many cases it is really hard to do so for the compiler, and if it makes it to the product the problem is that different parts of the code will have a different interpretation of what the object is like, and whenever those interpretations don't match you have a recipe for disaster.Uranography
I
3

What does it mean to maintain binary compatibility to you?

The object layout will be the same, but you will be breaking the One Definition Rule unless you recompile all code, at which point binary compatibility is basically useless. Without recompiling, then the ODR is broken, and while it might be the case that it works, it might also not work.

In particular if all of the virtual methods in the class are either pure or defined inline, then the compiler might generate the vtable in each translation unit that includes the header and mark it as a weak symbol. Then the linker will pick one of them and discard all the others. In this situation the linker is not required to verify that all of the vtables are exactly the same and will pick one at random (or deterministically in an undefined way), and it might pick one such vtable where the method is pure virtual, which in turn might end up crashing the application if the method is called on an object of the base class.

Ison answered 19/7, 2011 at 16:31 Comment(2)
In my case not all the virtual methods are pure, there's a mixture. I guess I'll rebuild everything anyway though, rather than live with the uncertainty.Sawmill
Specifically I had N shared libraries. I'm only calling the virtual function via a base class pointer in the first lib; the other N-1 libs contain derived classes with re-implementations of that function. I'd planned to change the pure to a non-pure and recompile the first library only.Sawmill

© 2022 - 2024 — McMap. All rights reserved.