Практически никак. Суть полиморфизма в том, что экземпляры наследников можно вставлять вместо экземпляра предка везде и все будет работать. Поэтому вы средствами языка никак не запретите передавать C вместо B (речь об указателях, естественно). Если хочется, то можно сделать виртуальную функцию, которая возвращала бы какое-то enum, для идентификации классов A,B,C (и других наследников) и уже в функции проверять, что там не передали по ошибке экземпляр C. Но логичнее было бы выделить каие-то свойства у классов (например, количество пуль в вашем примере с MultiGun) их задать в виртуальных функциях у всех классов и дальше в функции проверять, что переданный экземпляр обладает нужными свойствами. Жестко привязываться, что можно B, но нельзя C - это плохой подход. Почему нельзя? А если потом появится D,E,F - можно ли их передавать? А если они братья B?