Этот тип паттерна довольно распространен. Я не эксперт по C ++, но в Java вы видите это везде. Динамическое приведение представляется необходимым, потому что компилятор не может сказать, какую фабрику вы сохранили на карте. Насколько мне известно, с нынешним дизайном мало что можно сделать по этому поводу. Было бы полезно узнать, как эти объекты предназначены для использования. Позвольте мне привести пример того, как подобная задача выполняется в библиотеке баз данных Java (JDBC):
В системе есть DriverManager, который знает о драйверах JDBC. Водители должны быть как-то зарегистрированы (детали не важны); после регистрации каждый раз, когда вы запрашиваете соединение с базой данных, вы получаете объект Connection. Обычно этот объект будет OracleConnection или MSSQLConnection или чем-то подобным, но клиентский код видит только «Соединение». Чтобы получить объект Statement, вы говорите connection.prepareStatement, который возвращает объект типа PreparedStatement; за исключением того, что это действительно OraclePreparedStatement или MSSQLPreparedStatement. Это прозрачно для клиента, поскольку фабрика для операторов находится в соединении, а фабрика для соединений - в DriverManager.
Если ваши классы связаны друг с другом, вы можете захотеть иметь функцию, которая возвращает определенный тип класса, так же как метод getConnection DriverManager возвращает Connection. Кастинг не требуется.
Другой подход, который вы можете рассмотреть, - это использование фабрики, у которой есть фабричный метод для каждого конкретного класса, который вам нужен. Тогда вам понадобится только одна фабрика-фабрика, чтобы получить экземпляр фабрики. Пример (извините, если это неправильно C ++):
class CClassFactory
{
public:
virtual CBaseClass* CreateBase() { return new CBaseClass(); }
virtual CFooBaseClass* CreateFoo() { return new CFooBaseClass();}
}
class CAImplClassFactory : public CClassFactory
{
public:
virtual CBaseClass* CreateBase() { return new CAImplBaseClass(); }
virtual CFooBaseClass* CreateFoo() { return new CAImplFooBaseClass();}
}
class CBImplClassFactory : public CClassFactory // only overrides one method
{
public:
virtual CBaseClass* CreateBase() { return new CBImplBaseClass(); }
}
Что касается других комментариев, критикующих использование наследования: по моему мнению, нет никакой разницы между интерфейсом и публичным наследованием; так что продолжайте и используйте классы вместо интерфейсов везде, где это имеет смысл. Чистые интерфейсы могут быть более гибкими в долгосрочной перспективе, но, возможно, нет. Без подробностей о вашей иерархии классов невозможно сказать.