By using the g++ -S main.cpp to generate main.s, we can see that _ZN4BaseD1Ev is an alias for _ZN4BaseD2Ev. I believe this is a compiler optimization: in the absence of virtual base classes, the complete object destructor can reuse the implementation of the base object destructor, that is, both share the same code.
.size _ZN4BaseD2Ev, .-_ZN4BaseD2Ev
.weak _ZN4BaseD1Ev
.set _ZN4BaseD1Ev,_ZN4BaseD2Ev