And what do you mean by "stuff the data into the prototype functions"?
Do you mean something like this?:
I mean that the prototype functions take the tiles unique data as parameter. In fact, forget that and just pass a pointer to the actual tile, since the function might have to modify the tile (activating a door will obviously have to change its state).
If you need more functions, you add more and default initialize to 0 (or use empty virtual functions). Sure, you can just create one huge switch/case function for every event based on the type, but which one makes more sense very much depends on how flexible you want to be in terms of modding and extending. The switch/case version is for example a lot easier to debug, because the code is clearly telling you what goes where in a single place.
How many events will you need? Typical stuff like "onEntered", "onActivated", "onHit" and maybe quite important "onUpdate". The key is to be generic with your events and not just code reactions. So no "onZombieEntersWearingMetalArmor" and no "dealDamageToZombie" but simply "onEntered". Let the function figure out what entered and how to respond.
At the same time you shouldn't spend too much time on finding "the one true way to do it", because such a thing doesn't exist. Else you could argue that a vector of vector might not be as cache friendly and convenient to iterate over than a regular vector of size x*y. If you have a very good idea of what you want to do you can make plans and decisions. If you don't, trying to prepare for "everything you ever may like to do" will very efficiently keep you from ever really getting started.
Another thing is: only one tile per cell? What if I want to use "stone floor" and "wooden chair"? Would there be tons of tiles for each combination of "floor type" and "object on floor"? Not saying you should go overboard, but for example JA2 has a ton of layers in its map (ground, objects, structures, shadow, mercs, roof, onroof) AND each cell on each layer can have any number of tile elements. Of course the main reason for all those layers is that its a 2D iso engine. If you use actual 3D tiles or a simple top down view (where tiles don't overlap), you won't have to worry quite as much about what to draw when.