Virtual fields are processed at runtime. When you query the index with the Sitecore search context, the field is calculated and filled. A virtual field is not in the on disk index.
Computed fields are processed when the index is generated (traditional). These are physically on disk in the index.
Virtual fields are expensive because they require the fields to be generated when the query is run. Computed fields are generated when the index is generated. making the search API request vey fast. On most cases computed fields should be used since all the work is on the indexer and the index server. If virtual fields are used, care should be taken to make sure the results are cached.
A good example of virtual field is a daterange field that turns absolute value of __smallcreateddate, like 20171014 into a relative value like thismonth. This value cannot be stored in index because it quickly become out of date. It has to be calculated when the query is run.
https://www.kasaku.co.uk/2015/08/16/implementing-a-virtual-field-in-sitecore/