Music collection with lyric songs and instrumental pieces
Polymorphic classes must include a virtual destructor. Otherwise they are not truly polymorphic: you cannot delete such an instance using the pointer to the base class.

A class hierarchy should (typically) be designed according to the Liskov Substitution Principle. This means that any derived class must be substitutable for the base class: anywhere a base class is expected to work, the derived class must as well. Your hierarchy conforms to this, but I wanted to point it out.


  Will there be a way to know what type of Song I work with, in case of iterating over an array of Song pointer that point to various song types?


That's what dynamic_cast is for - it returns nullptr when the object is not of the desired type.

Song * song = ...;
auto isong = dynamic_cast&lt;InstrumentalSong*&gt;(song);
if (isong) { 
  /* it's instrumental */
  ...
}
auto lsong = dynamic_cast&lt;LyricSong*&gt;(song);
if (lsong) {
  /* it's lyric */
  ...
}


The type of isong is deduced to InstrumentalSong*, etc.

A basic question to be asked is: do you even care about a class structure? What do you do with all that song data?