2011-08-25 99 views
7

我有下面的代码不能编译。带接口对象的C++模板

class Base { 
    public: 
     virtual ~Base() { }; 
}; 

class Derived : public Base { }; 

class NotDerived { }; 

template <typename T> 
class Group { }; 

int main() { 
    Group<Base> *g = NULL; 

    g = new Group<Base>();  // Works 
    g = new Group<Derived>(); // Error, but I want it to work 

    g = new Group<NotDerived>(); // Error, as expected 
} 

我明白,这不能编译,因为g是不同的类型Group<Derived>。为了在Java中完成这项工作,我会做一些事情,例如Group<? extends Base> g,但据我所知C++没有那个关键字。可以做什么?

编辑:我想澄清一下,我不希望它有可能将Base的类型设置为g。我已经更新了我的例子来解释这一点。

编辑2:我的问题有两种解决方案。 Dave's我发现很简单,很容易定义。但Bowie's(加上Mark's)更适合我的需求。

+0

我不熟悉Java是如何工作的。你想用这种语法说什么? –

+0

这在Java中也不起作用。 '<?的语法扩展...>不是为了支持协方差,而是在那里为泛型可能使用的类型添加约束。 –

+0

请参阅[C++模板多态性](http://stackoverflow.com/questions/2203388/c-templates-polymorphism) – Praetorian

回答

3

你可以让集团<数据库>基类的所有<集团T> T!=基地。

class Base { 
    public: 
     virtual ~Base() { }; 
}; 

class Derived : public Base { }; 


template <typename T> class Group; 

struct Empty { }; 

template <typename T> 
struct base_for_group_t { 
    typedef Group<Base> type; 
}; 

template <> 
struct base_for_group_t<Base> { 
    typedef Empty type; 
}; 

template <typename T> 
class Group : public base_for_group_t<T>::type { }; 

int main() { 
    Group<Base> *g = 0; 

    g = new Group<Base>(); // Works 
    g = new Group<Derived>(); // now works 
} 
+0

不幸的是,现在像这样的东西是合法的:'class NotDerived {}; g =新组();'。如果可能,我想保持类型安全。 – Ryan

1

我不认为C++支持。 C++ Template在编译时完全处理,因此它不支持多态性。这意味着模板参数的类型应该对赋值表达式的两侧完全相同。

5

的类Group<Base>Group<Derived>是完全不相关的,不同的类。指向他们的方向不可转换。

如果你需要运行时多态性的行为,你的类模板Group可以从普通(非模板)基类派生:

class Group // base 
{ 
    virtual ~Group() { } 
}; 

template <typename T> 
class ConcreteGroup : public Group 
{ 
    // ... 
    T * m_impl; 
}; 

Group * g1 = new ConcreteGroup<A>; 
Group * g1 = new ConcreteGroup<B>; 
+0

ConcreteGroup不需要继承Group? –

+0

@穆:是的,谢谢,修好! –

2

Bowie Owens's Answer处理您需要解决原始问题的协方差。至于你在编辑问题中所要求的限制 - 你可以通过使用类型特征来实现。

template <typename T, class Enable = void> class Group; 

template <typename T> 
class Group<T, typename enable_if<is_base_of<Base, T>::value>::type> 
    : public base_for_group_t<T>::type { }; 
+0

不幸的是,我无法得到它在我的最终编译(我不熟悉如何正确使用类型特征)。你能提供一个更完整的例子吗? (我认为'Group '应该是'template class Group',但是这不起作用。 – Ryan

+0

再次用':: value 'on is_base_of。(boost :: enable_if'和'std :: enable_if'之间的区别)如果不是,你得到的错误是什么? –

+0

啊,我没有包含std命名空间,你原来的代码按预期工作。 ;) – Ryan

0

我想我明白你要做什么。我不确定这是最好的方法(你可能想看看Boost.Factory)。

template <class T> 
class Factory { 

public: 
    virtual T* operator()() = 0; 
}; 

template <class Derived, class Base> 
class ConcreteFactory : public Factory<Base> { 

public: 
    virtual Base* operator()() { 
    return new Derived(); 
    } 
}; 

class Base { 
public: 
    virtual ~Base() {}; 
}; 

class Derived1 : public Base { }; 
class Derived2: public Base {}; 

class NotDerived {}; 

int main() 
{ 
    Factory<Base>* g; 

    g = new ConcreteFactory<Derived1, Base>; 
    g = new ConcreteFactory<Derived2, Base>; 
    // g = new ConcreteFactory<NotDerived, Base>; // Will not work if you try to do this 
} 
+0

这似乎是迄今为止最安全的解决方案。 Derived1和Base的定义有点多余,但这不是我已经不知道的(我可以用typedef来避免)。谢谢, :) – Ryan