Now go back and re-read the previous paragraph, but make these substitutions:
After this, you'll have a working definition of virtual data.
Another way to look at this is to distinguish "per-object" member functions from "dynamic" member functions. A "per-object" member fn is a member fn that is potentially different in any given instance of an object, and could be implemented by burying a function ptr in the object; this pointer could be "const", since the pointer will never be changed throughout the object's life. A "dynamic" member fn is a member fn that will change dynamically over time; this could also be implemented by a function ptr, but the fn ptr would not be const.
Extending the analogy, this gives us three distinct concepts for data members:
The reason they all look so much the same is that none of this is "supported" in C++. It's all merely "allowed," and in this case, the mechanism for faking each of these is the same: a ptr to a (probably abstract) base class. In a language that made these "first class" abstraction mechanisms, the difference would be more striking, since they'd each have a different syntactic variant.