The specification of the thread function is not correct. Use
_beginthread (&gangplank, 0, (void *)this);
In addition, you should wait in the destructor of your thread until the newly created workerthread has ended. What happens now is that in main you create a "d" object, call its start() function, and then terminate main. This will destroy the "d" object, even before the thread had a chance to run. Then, when the thread's worker function is finally called, the "d" object has already been destroyed, and hence its v-table is invalid. But this v-table is needed to call a virtual function. This is also the reason why your example runs without declaring the run function as virtual. In that case the v-table is not needed and it doesn't matter that the "d" object is already gone.
As a simple test, put a Sleep (1000) before the call of _endthread. Eventually you will need a more sophisticated thread termination sequence.
And there is one more problem in your code: _endthread must be called from the thread that you want to terminate. Instead it is called here from the main thread. That even makes things worse. Your thread function ends anyway after you do "cout << 2". So there is actually no need to call _endthread. If you are going to extend your example to a full application, you want to put _endthread into you run function.