query_posts()might be used in one and only case if you need to modify main query of page (for which there are better and more reliable methods to accomplish, over simplistic approach of this function). It sets a lot of global variables and will lead to obscure and horrible bugs if used in any other place and for any other purpose;
get_posts()is very similar in mechanics and accepts same arguments, but returns array of posts, doesn’t modify global variables and is safe to use anywhere;
WP_Queryclass power both behind the scenes, but you can also create and work with own object of it. Bit more complex, less restrictions, also safe to use anywhere.
I want to stress that
query_posts() wrongfully overused in many tutorials around. It is one of the most widespread bad practices.