【发布时间】:2017-03-09 07:32:36
【问题描述】:
(Java)Collection in C++ 没有类似的概念。
我可以理解原因,但我想知道有没有什么方法可以优雅地伪造。
示例
我已经实现了许多自定义Collections。
它们都有 Iterator 可以正常工作,类似于 std::vector、std::unordered_set 等。
他们是MyArray<T>、MyBinaryTree<T>和MySet<T>。
在这里,我将显示一个工作代码,显示我想要伪造它的位置。
假设我有 2 个级别的程序:库和用户。
它只做一件事——User 命令Library 吃掉一个桶里的所有Orange*s。
图书馆.h
class Library{
public: static void eatAll(const MyArray<Orange*>& bucket);
};
库.cpp
#include "Orange.h"
void Library::eatAll(const MyArray<Orange*>& bucket){
for(auto orange:bucket){
orange->eaten();
}
}
User.h
MyArray<Orange*> bucket;
Library::eatAll(bucket);
没关系。
现在,我希望Library::eatAll 也支持MyBinaryTree<Orange*>,我有一些不太理想的方法如下。
我的糟糕解决方案
1。 Java方式
- 使
MyBinaryTree<T>和MyArray<Orange*>(及其迭代器)继承自一个新类Collection<T>(和CollectionIterator<T>)。 - 将签名更改为
Library::eatAll(const Collection<T>&)
缺点:Collection<T> 中某些功能的“虚拟”性能损失。
2。模板 v1
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
orange->eaten();
}
}
- 使
eatAll成为模板函数
缺点:eatAll的实现必须在header中。
我必须在Library.h 中#include orange.h。
有时候,我真的只想转发声明。
3。模板 v2
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
eatAnOrange(orange)
}
}
private: void eatAnOrange(Orange* orange){
//below implementation is inside Library.cpp
orange->eaten();
}
- 创建中间人函数
eatAnOrange
缺点:
- 代码可读性差,不简洁,导致一点可维护性问题。
- 如果有很多其他功能,例如
squeezeAll(),我可能需要创建很多中间人功能,例如squeezeAnOrange()。
4。运算符=()
通过隐式构造函数在 3 个集合类之间创建转换器。
缺点:创建新的集合实例会降低性能。
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
我认为我的解决方案并不优雅。
有没有没有上述缺点的解决方案?
编辑:
当前的两个答案都比我的方法优雅(谢谢!),但仍然有缺点:-
- Oliv 需要 #include "orange.h" 在 User.h。
- Richard Hodges 有虚函数调用。
【问题讨论】:
-
您可能可以键入擦除集合并拥有一个接受公共基类的非模板函数,但这会引入虚拟调用(这就是 Java 所具有的,作为接口的基类) .否则,将您的函数设为函数模板,其中
T是容器,而不是包含的类型。 -
@skypjack 感谢您提供替代解决方案,skypack! ...
T是容器 = 我的“模板方式 1”吗? -
Container Concept 最接近您的想法。
-
@R Sahu 谢谢,新的“概念”涵盖了非常广泛的领域!您是否在实践中使用过 Concept(C++ 实验性功能),即是否已经亲自采用?
-
您应该记住的模型是,虽然 java 在运行时多态性(通过虚函数实现)方面很重要,但 C++ 在编译时间方面很重要多态性(通过模板实现)。
标签: c++ c++11 templates containers