没有类似的(Java)概念 用C ++收集。
我能理解其中的原因,但我想知道是否有办法解决 假 它很优雅。
例
我已经实现了很多自定义 Collection
秒。
他们都有 Iterator
这是正常的,类似于 std::vector
, std::unordered_set
等
他们是 MyArray<T>
, MyBinaryTree<T>
和 MySet<T>
。
在这里,我将展示一个工作代码,显示我想要伪造它的位置。
假设我有两个级别的程序:库和用户。
它只做一件事 - User
命令 Library
吃所有 Orange*
在一个桶里。
Library.h
class Library{
public: static void eatAll(const MyArray<Orange*>& bucket);
};
Library.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
必须在标题中。
我不得不 #include orange.h
在 Library.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();
}
坏处 :
- 代码不太可读,不简洁,导致一点可维护性问题。
- 如果还有很多其他功能,例如
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
。
- 理查德·霍奇斯的虚拟函数调用。
在C ++中,使用迭代器设计模式遍历集合。整个STL是围绕这个概念设计的。它可能适合您的需求:
你可以定义 eatAll
作为接受两个迭代器的函数:
template<class Iterator,class Sentinel>
void eatAll(Iterator it, Sentinel s){
for (;it!=s;++it)
it->eaten();
}
或者 范围就像 算法接口:
template<class Range>
void eatAll(Range& r){
for (auto& v:r)
v.eaten();
}
您必须将二叉树定义为范围(它必须实现 begin()
和 end()
)。希望树木是一种可以线性化的图形。然后,所有智能工作都将进入迭代器实现!
如果你想要它真正的多态,那么我们必须处理两件事:
容器的实际类型
解除引用映射的结果是包含键和值引用的对的事实。
我的观点是,对此的答案不是从容器派生,这是限制,而是创建一个多态“值迭代器”,它模拟所有迭代器并正确提取它们的值。
然后我们可以编写如下代码:
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}
要得到这个:
vector:
Orange
Orange
map:
Orange
Orange
Orange
这是一个最小的,完整的实现:
#include <typeinfo>
#include <memory>
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
// define an orange
struct Orange {
};
// a meta-function to get the type of the value of some iterated value_type
template<class ValueType> struct type_of_value
{
using type = ValueType;
};
// specialise it for maps and unordered maps
template<class K, class V> struct type_of_value<std::pair<K, V>>
{
using type = V;
};
template<class ValueType> using type_of_value_t = typename type_of_value<ValueType>::type;
// function to extract a value from an instance of a value_type
template<class ValueType> struct value_extractor
{
template<class V>
auto& operator()(V&& v) const {
return v;
}
};
// specialised for maps
template<class K, class V> struct value_extractor<std::pair<K, V>>
{
template<class Arg>
auto& operator()(Arg&& v) const {
return std::get<1>(v);
}
};
template<class Iter>
auto extract_value(Iter const& iter) -> auto&
{
using value_type = typename std::iterator_traits<Iter>::value_type;
auto e = value_extractor<value_type> {};
return e(*iter);
}
// a polymorphic (forward only at the moment) iterator
// which delivers the value (in the case of maps) or the element (every other container)
template<class ValueType>
struct PolymorphicValueIterator {
using value_type = type_of_value_t<ValueType>;
private:
struct iterator_details {
std::type_info const &type;
void *address;
};
struct concept {
virtual std::unique_ptr<concept> clone() const = 0;
virtual value_type& invoke_deref() const = 0;
virtual void invoke_next(std::size_t distance = 1) = 0;
virtual iterator_details get_details() = 0;
virtual bool is_equal(const iterator_details &other) const = 0;
virtual ~concept() = default;
};
template<class Iter>
struct model final : concept {
model(Iter iter)
: iter_(iter)
{}
std::unique_ptr<concept> clone() const override
{
return std::make_unique<model>(iter_);
}
virtual value_type& invoke_deref() const override {
return extract_value(iter_);
}
void invoke_next(std::size_t distance = 1) override
{
iter_ = std::next(iter_, distance);
}
iterator_details get_details() override {
return {
typeid(Iter),
std::addressof(iter_)
};
}
bool is_equal(const iterator_details &other) const override {
if (typeid(Iter) != other.type) {
return false;
}
auto pother = reinterpret_cast<Iter const*>(other.address);
Iter const& iother = *pother;
return iter_ == iother;
}
Iter iter_;
};
std::unique_ptr<concept> concept_ptr_;
public:
bool operator==(PolymorphicValueIterator const &r) const {
return concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
bool operator!=(PolymorphicValueIterator const &r) const {
return not concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
PolymorphicValueIterator &operator++() {
concept_ptr_->invoke_next(1);
return *this;
}
value_type& operator*() const {
return concept_ptr_->invoke_deref();
}
template<class Iter>
PolymorphicValueIterator(Iter iter)
{
concept_ptr_ = std::make_unique<model<Iter>>(iter);
}
PolymorphicValueIterator(PolymorphicValueIterator const& r)
: concept_ptr_(r.concept_ptr_->clone())
{}
PolymorphicValueIterator& operator=(PolymorphicValueIterator const& r)
{
concept_ptr_ = r.concept_ptr_->clone();
return *this;
}
};
template<class Iter>
auto makePolymorphicValueIterator(Iter iter)
{
using iter_value_type = typename std::iterator_traits<Iter>::value_type;
using value_type = type_of_value_t<iter_value_type>;
return PolymorphicValueIterator<value_type>(iter);
}
// a test
void do_orange_things(PolymorphicValueIterator<Orange> first, PolymorphicValueIterator<Orange> last)
{
while(first != last) {
std::cout << "Orange\n";
++first;
}
}
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}