Wes McKinney <wesmck...@gmail.com> writes: > The abstract/all-virtual base has some benefits: > > * No need to implement "forwarding" methods to the private implementation > * Do not have to declare "friend" classes in the header for some cases > where other classes need to access the methods of a private > implementation > * Implementation symbols do not need to be exported in DLLs with an > *_EXPORT macro > > There are some drawbacks, or cases where this method cannot be applied, > though: > > * An implementation of some other abstract interface which needs to > appear in a public header may not be able to use this approach. > * My understanding is that the PIMPL pattern will perform better for > non-virtual functions that are called a lot. It'd be helpful to know > the magnitude of the performance difference > * Complex inheritance patterns may require use of virtual inheritance, > which can create a burden for downstream users (e.g. they may have to > use dynamic_cast to convert between types in the class hierarchy)
I would add these two points, which may or may not be a significant concern to you: * When you add new methods to the abstract virtual model, you change the ABI [1] and therefore need to recompile client code. This has many consequences for distribution. * PIMPL gives a well-defined place for input validation and setting debugger breakpoints even when you don't know which implementation will be used. [1] The ABI changes because code to index into the vtable is inlined at the call site. Adding to your example void foo(VirtualType &obj) { obj.Method1(); // any other line to suppress tail call } produces assembly like mov rax,QWORD PTR [rdi] ; load vtable for obj call QWORD PTR [rax+0x10] ; 0x10 is offset into vtable A different method will use a different offset. If you add a method, offsets of existing methods may change. With PIMPL, the equivalent indexing code resides in your library instead of client code, and yields a static (or PLT) call resolved by the linker: call _ZN9PIMPLType7Method1Ev@PLT