Подобной концепции (Java) нет в коллекции С++.
Я могу понять причину, но я хочу знать, есть ли способ подделка. Элегантно.
Пример
Я реализовал множество пользовательских Collection
s.
Все они имеют Iterator
, который работает правильно, подобно std::vector
, std::unordered_set
и т.д.
Они MyArray<T>
, MyBinaryTree<T>
и MySet<T>
.
Здесь я покажу рабочий код, который показывает местоположение, которое я хочу подделать.
Скажем, что у меня есть 2 уровня программы: библиотека и пользователь.
Только одно: 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
функцию шаблона
Недостаток: Реализация 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();
}
- создать функцию среднего человека
eatAnOrange
Недостаток:
- Код менее читабельный, а не краткий, вызывает небольшую проблему ремонтопригодности.
- Если есть много других функций, например.
squeezeAll()
, мне, вероятно, нужно создать много функций среднего человека, например.squeezeAnOrange()
.
4. Оператор =()
Создайте конвертер из 3 классов коллекции через неявный конструктор.
Недостаток: Страдает от создания нового экземпляра коллекции.
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
Я считаю, что мои решения неэлегантны.
Существуют ли какие-либо решения, которые не имеют упомянутого недостатка?
Edit:
Оба текущих ответа элегантны, чем мои подходы (спасибо!), Но все еще имеют недостаток: -
- Оливу требуется #include "orange.h"
в User.h
.
- Ричард Ходжес имеет вызов виртуальной функции.