The question is mostly concerned with OOPS technique.
The following is the quote from ovm cookbook.
Quote:
The start_item() API will
look to see if the object passed in is a sequence item or a sequence. If it’s a
sequence, it will initiate execution on m_sequencer. If it’s a sequence item, it
will send it to the driver. So, start_item() provides a polymorphic way to
initiate execution of sequences and sequence items
The important thing to note is how sequence determines if the passed object is a sequence or a sequence item. Is there a method within SV/OOPS to determine this or this has to be taken care as a part of implementation. For example, in sequence_items, I would set a specific flag and I would set a different flag for sequences. This way, I will know what is being passed.

This is what is called polymorphism in OOP. Because a sequence is extended from a sequence_item, you can call a different virtual method based on the type of the class.
BTW, this mechanism has been deprecated in the UVM. You should be using seq.start() to start a sequence.
Dave Rich
Mentor Graphics
http://go.mentor.com/drich
Maybe I am wrong but the way I understand polymorphism is that different set of code get executed in the callee side even though the caller does not know about it ...
While in the above case, it seems as if the sequence first determines if the called object is a sequence type or a sequence_item type and then makes different call(s) altogether.
If start_item was present in sequence and in sequence_item then the above explanation would make sense to me since I can execute completely different pieces of code since implementation of start_item can be different in these two classes
polymorphism works well when the API is exactly the same between different sets of code. Remember that you have to execute start_item/finish_item as a pair, versus just start(). There are other differences in the required sets of arguments needed to the methods as well.
Dave Rich
Mentor Graphics
http://go.mentor.com/drich