Rus*_*rse 29 c++ polymorphism templates
我有这种类的结构.
class Interface{
...
}
class Foo : public Interface{
...
}
template <class T>
class Container{
...
}
Run Code Online (Sandbox Code Playgroud)
我有一些其他类Bar的构造函数.
Bar(const Container<Interface> & bar){
...
}
Run Code Online (Sandbox Code Playgroud)
当我以这种方式调用构造函数时,我得到"无匹配函数"错误.
Container<Foo> container ();
Bar * temp = new Bar(container);
Run Code Online (Sandbox Code Playgroud)
怎么了?模板不是多态的吗?
Luc*_*lle 39
我认为你需要的确切术语是"模板协方差",这意味着如果B继承自A,那么某种方式T<B>继承自T<A>.这不是C++中的情况,也不是Java和C#泛型*.
避免模板协方差是有充分理由的:这将简单地删除模板类中的所有类型安全性.让我用以下示例解释一下:
//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!
}
Run Code Online (Sandbox Code Playgroud)
因此,无论A和B之间的关系如何,您都应该考虑T<A>并将其T<B>视为完全不相关的类型.
那你怎么能解决你所面临的问题呢?在Java和C#中,您可以分别使用有界通配符和约束:
//Java code
Bar(Container<? extends Interface) {...}
//C# code
Bar<T>(Container<T> container) where T : Interface {...}
Run Code Online (Sandbox Code Playgroud)
下一个C++标准(称为C++ 1x(以前称为C++ 0x))最初包含一个名为Concepts的更强大的机制,它可以让开发人员对模板参数强制执行语法和/或语义要求,但不幸的是推迟到以后的日子.但是,Boost有一个您可能感兴趣的概念检查库.
然而,对于遇到的问题,概念可能有点过分,使用@gf提出的简单静态断言可能是最好的解决方案.
*更新:自.Net Framework 4以来,可以将通用参数标记为协变或逆变.
Geo*_*che 11
这里有两个问题:默认结构有形式MyClass c;; 使用括号,它看起来像编译器的函数声明.
另一个问题是它Container<Interface>只是一个不同的类型Container<Foo>- 你可以做以下事实而不是实际获得多态性:
Bar::Bar(const Container<Interface*>&) {}
Container<Interface*> container;
container.push_back(new Foo);
Bar* temp = new Bar(container);
Run Code Online (Sandbox Code Playgroud)
或者当然,你可以Bar像Kornel所展示的那样使它或它的构造函数成为模板.
如果你真的想要一些类型安全的编译时多态,你可以使用Boost.TypeTraits is_base_of或一些等价物:
template<class T>
Bar::Bar(const Container<T>& c) {
BOOST_STATIC_ASSERT((boost::is_base_of<Interface, T>::value));
// ... will give a compile time error if T doesn't
// inherit from Interface
}
Run Code Online (Sandbox Code Playgroud)
不.想象一下,容器参数被"硬编码"到它定义的类中(实际上它是如何工作的).因此容器类型Container_Foo是不兼容的Container_Interface.
你会尝试的是这个:
template<class T>
Bar(const Container<T> & bar){
...
}
Run Code Online (Sandbox Code Playgroud)
然而,你放松了直接类型检查.
实际上STL方式(可能更有效和通用)是可行的
template<class InputIterator>
Bar(InputIterator begin, InputIterator end){
...
}
Run Code Online (Sandbox Code Playgroud)
...但我假设您没有在容器中实现迭代器.
| 归档时间: |
|
| 查看次数: |
22433 次 |
| 最近记录: |