The common implementation of dynamic dispatch in C++ is by means of a virtual table, which is basically an array of pointers to functions, one for each virtual function in the type. The length of the inheritance chain does not matter, since the vtable holds only one pointer, that of the final overrider for that particular function in the complete object. It will be a single indirection whether the final overrider is in the base or a hundred levels from it.
Multiple inheritance can have a small impact in performance, the amount of which will depend on the actual implementation, but will be independent of the number of bases. In the case of single inheritance the base and the derived object are aligned in memory, that the value of a pointer to the derived type, will have the same address as the same pointer converted to pointer to the base type. In the case of multiple inheritance (assuming that bases are not empty), that is not the case. Only the first base[*] can be aligned with the full object.
The implication of the lack of alignment is that the this
pointer will need to be adjusted to point to the appropriate location, depending on which is the final overrider of the virtual function in the complete object. A naïve implementation could store both the offset and the pointer to the function in the vtable, use the offset to adjust the pointer, then jump to the function. This would imply an addition (of possibly 0) to the this
pointer for every call to the virtual function. In real life, compilers usually store a single pointer to function that will refer to either the final overrider if the this
pointer does not need to be adjusted or to a small trampoline function that will offset the this
pointer and forward to that overrider.
You explicitly mentioned that you are not really interested in virtual inheritance, and I will skip the complex further explanations. All of the above is already a bit of a simplification, but hopefully you get the idea. The height of the inheritance chain does not matter, the width can have a very small impact (an extra jump and an addition, or some similar costs, depending on the implementation.
If you are interested, I recommend that you pick up The C++ Object Model by Lippman. Even if the book is over 15 years old, and contains typos and so forth, it describes many of the issues in implementing the object model and comments on some of the solutions.
[*] With the Empty Base Optimization, this becomes all of the empty bases and the first non-empty base.