I learned quite quickly, the hard way, that including a collision detection routine on each bullet as a separate class was not the way to go.
Like retlaf said, data oriented design is important when looping through potentially hundreds of visible objects, and you don't want the actual code to jump between every object on screen. I've come up with two ways to do it.
Either keep references to all the hitboxes as direct data members of the stage, with dimension information and a reference to the object that owns it, and have the stage itself calculate what's colliding, only referring to other objects when there's an actual collision.
Or keep all the bullets as data members of the pattern class, and have each pattern figure out if either of its bullets are colliding with any enemy or player.
I think I prefer the first method, even though it's very OOP-ugly, it seems to be the sensible thing to do. In order to avoid spending time on bullet-on-bullet collision I keep different kinds of hitboxes in different collectios (a player, playerbullet, enemy and enemybullet).