Наименьшее изменение в вашем коде будет меняться:
class SubObjectInt : public SubObject<int>
{
};
до
typedef SubObject<int> SubObjectInt;
Текущее ошибочное определение теперь скомпилируется и вернет действительный указатель.
Если вы хотите, чтобы конкретный код был специфичным для SubObjectInt, отличным от SubObject, вместо этого вы могли бы иметь:
template<class T>
class SubObject : public Object
{
public:
typedef SubContainer<SubObject<T> > ContainerType;
ContainerType* GetSubContainer()
{
Container* container = GetContainer();
return dynamic_cast<ContainerType*>(container);
}
void TestMe()
{
ContainerType* pSubContainer = GetSubContainer();
assert(pSubContainer);
}
};
И тогда ваш тестовый код выглядит примерно так:
SubObjectInt::ContainerType* pContainer = new SubObjectInt::ContainerType();
SubObjectInt* pObject = new SubObjectInt();
pContainer->SetObject(pObject);
pObject->TestMe();
РЕДАКТИРОВАТЬ: в ответ на первый комментарий
ну, я бы сказал, что вам может быть лучше использовать другой дизайн, вы смешиваете наследование, композицию и шаблоны таким образом, что усложняет то, что, я думаю, вы хотите достичь.
у вас есть тип контейнера, который вы хотите иметь возможность назначать объекты.
у вас есть тип объекта, который хочет знать о своем контейнере.
вы хотите, чтобы типы контейнеров и объектов выполняли одни и те же функции, а некоторые по-разному в зависимости от их содержимого.
я бы предложил что-то вроде этого:
template<class T>
class ObjectStrategy
{
public:
virtual void execute(T* object)
{
std::cout << "oh noes i am a default general ObjectStrategy" << std::endl;
}
};
template<class T>
class ContainerStrategy
{
public:
virtual void execute(T* container)
{
std::cout << "oops i am a default general ContainerStrategy" << std::endl;
}
};
template<class T>
class Object;
template<class T>
class Container
{
public:
Container() : m_pObject(0), m_strategy(new ContainerStrategy<Container<T> >()) { }
Container(ContainerStrategy<Container<T> >* strategy_override) : m_pObject(0), m_strategy(strategy_override) { }
~Container() { delete m_strategy; }
void SetObject(T* pObject)
{
m_pObject = pObject;
m_pObject->SetContainer(this);
}
void DoContainerStuff()
{
m_strategy->execute(this);
}
protected:
T* m_pObject;
ContainerStrategy<Container<T> >* m_strategy;
};
template<class T>
class Object
{
public:
Object() : m_pContainer(0), m_strategy(new ObjectStrategy<Object<T> >()) { }
Object(ObjectStrategy<Object<T> >* strategy_override) : m_pContainer(0), m_strategy(strategy_override) { }
~Object() { delete m_strategy; }
Container<Object<T> >* GetContainer()
{
return m_pContainer;
}
void SetContainer(Container<Object<T> >* pContainer)
{
m_pContainer = pContainer;
}
void DoObjectStuff()
{
m_strategy->execute(this);
}
void TestMe()
{
DoObjectStuff();
Container<Object<T> >* pContainer = GetContainer();
pContainer->DoContainerStuff();
}
protected:
Container<Object<T> >* m_pContainer;
ObjectStrategy<Object<T> >* m_strategy;
};
typedef Object<int> ObjectInt;
template<>
class ObjectStrategy<ObjectInt>
{
public:
virtual void execute(ObjectInt* container)
{
std::cout << "omg i am a default specific strategy for ObjectInt" << std::endl;
}
};
typedef Container<ObjectInt> ContainerObjectInt;
template<>
class ContainerStrategy<ContainerObjectInt>
{
public:
virtual void execute(ContainerObjectInt* container)
{
std::cout << "pow i am a default specific strategy for ContainerObjectInt" << std::endl;
}
};
class ObjectIntOverrideStrategy : public ObjectStrategy<ObjectInt>
{
public:
virtual void execute(ObjectInt* object)
{
std::cout << "bam i am an overriding specific strategy for ObjectInt" << std::endl;
}
};
class ContainerObjectIntOverrideStrategy : public ContainerStrategy<ContainerObjectInt>
{
public:
virtual void execute(ContainerObjectInt* object)
{
std::cout << "woo i am an overriding specific strategy ContainerObjectInt" << std::endl;
}
};
int main(int argc, char** argv)
{
{ // test with default + general strategies
typedef Object<float> ObjectFloat;
typedef Container<ObjectFloat> ContainerObjectFloat;
ObjectFloat* pObject = new ObjectFloat();
ContainerObjectFloat* pContainer = new ContainerObjectFloat();
pContainer->SetObject(pObject);
pObject->TestMe();
}
{ // test with default + specific strategies
ObjectInt* pObject = new ObjectInt;
ContainerObjectInt* pContainer = new ContainerObjectInt;
pContainer->SetObject(pObject);
pObject->TestMe();
}
{ // test with overriding + specific strategies
ObjectInt* pObject = new ObjectInt(new ObjectIntOverrideStrategy);
ContainerObjectInt* pContainer = new ContainerObjectInt(new ContainerObjectIntOverrideStrategy);
pContainer->SetObject(pObject);
pObject->TestMe();
}
return 0;
}
общая функциональность объектов или контейнеров реализована как функции-члены объекта или контейнера соответственно.
функциональность объектов или контейнеров для каждого типа реализована с помощью композиции объектов стратегии, вы можете использовать фабрику для производства соответствующих объектов и контейнеров на основе соответствующих стратегий.
Я предложил довольно гибкий подход (возможно, слишком гибкий), чтобы вы могли игнорировать специализацию или наследование шаблонов для объектов стратегии в зависимости от того, насколько специфичным вам является поведение.