C ++模板多态性 [英] C++ Templates polymorphism
问题描述
我有这种结构的类。
类接口{
...
}
class Foo:public Interface {
...
}
template< class T>
class Container {
...
}
有一个其他类Bar的构造函数。
Bar(const Container< Interface>& bar){
。 ..
}
当我以这种方式调用构造函数时,错误。
容器< Foo>容器 ();
Bar * temp = new Bar(container);
有什么问题?不是模板多态?
我认为你需要的确切术语是模板协方差,意味着如果B继承从A,然后以某种方式 T
从 T
继承。这不是在C ++中的情况,也不是与Java和C#泛型*。
有一个很好的理由避免模板协方差:这将只是删除所有类型安全在模板类中。让我用下面的例子解释:
//假设下面的类层次结构
class Fruit {...} ;
class Apple:public Fruit {...};
class Orange:public Fruit {...};
//现在我将使用这些类型来实例化类模板,即std :: vector
int main()
{
std :: vector< Apple> ; apple_vec;
apple_vec.push_back(Apple()); //这里没有问题
//如果模板是协变的,以下是合法的
std :: vector< Fruit> & fruit_vec = apple_vec;
// push_back需要一个Fruit,所以我可以传递一个Orange
fruit_vec.push_back(Orange());
//哦不!我只是在我的苹果篮里添加了一个橙色!
}
因此,您应该考虑 T& / code>和
T
作为完全不相关的类型,而不管A和B之间的关系。
那么你如何解决你面对的问题呢?在Java和C#中,您可以分别使用有界通配符和约束:
// Java code
Bar(Container< ;? extends Interface){...}
// C#code
Bar< T&其中T:Interface {...}
下一个C ++标准以前的C ++ 0x))最初包含一个更强大的机制,名为概念,这将允许开发人员强制对模板参数的语法和/或语义要求,但不幸地推迟到以后的日期。但是,Boost有一个概念检查库,您可能会对此感兴趣。
然而,概念可能对你遇到的问题有点过分,使用一个简单的静态assert由 @ gf 可能是最好的解决方案。
*更新: 4,可以标记协变或逆变的通用参数。 / p>
I have this structure of classes.
class Interface{
...
}
class Foo : public Interface{
...
}
template <class T>
class Container{
...
}
And I have this constructor of some other class Bar.
Bar(const Container<Interface> & bar){
...
}
When I call the constructor this way I get "no matching function" error.
Container<Foo> container ();
Bar * temp = new Bar(container);
What is wrong? Are not templates polymorphic?
I think the exact terminology for what you need is "template covariance", meaning that if B inherits from A, then somehow T<B>
inherits from T<A>
. This is not the case in C++, nor it is with Java and C# generics*.
There is a good reason to avoid template covariance: this will simply remove all type safety in the template class. Let me explain with the following example:
//Assume the following class hierarchy
class Fruit {...};
class Apple : public Fruit {...};
class Orange : public Fruit {...};
//Now I will use these types to instantiate a class template, namely std::vector
int main()
{
std::vector<Apple> apple_vec;
apple_vec.push_back(Apple()); //no problem here
//If templates were covariant, the following would be legal
std::vector<Fruit> & fruit_vec = apple_vec;
//push_back would expect a Fruit, so I could pass it an Orange
fruit_vec.push_back(Orange());
//Oh no! I just added an orange in my apple basket!
}
Consequently, you should consider T<A>
and T<B>
as completely unrelated types, regardless of the relation between A and B.
So how could you solve the issue you're facing? In Java and C#, you could use respectively bounded wildcards and constraints:
//Java code
Bar(Container<? extends Interface) {...}
//C# code
Bar<T>(Container<T> container) where T : Interface {...}
The next C++ Standard (known as C++1x (formerly C++0x)) initially contained an even more powerful mechanism named Concepts, that would have let developers enforce syntaxic and/or semantic requirements on template parameters, but was unfortunately postponed to a later date. However, Boost has a Concept Check library that may interest you.
Nevertheless, concepts might be a little overkill for the problem you encounter, an using a simple static assert as proposed by @gf is probably the best solution.
* Update: Since .Net Framework 4, it is possible to mark generic parameters has being covariant or contravariant.
这篇关于C ++模板多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!