There are no similar concept of (Java) Collection in C++.
I can understand the reason, but I want to know whether there is any way to fake it elegantly.
Example
I have implemented many custom Collection
s.
They all have Iterator
that works correctly, similar to std::vector
, std::unordered_set
, etc.
They are MyArray<T>
, MyBinaryTree<T>
and MySet<T>
.
Here I will show a working code that show the location I want to fake it.
Let's say that I have 2 levels of program : library and user.
It does only one thing - User
commands Library
to eat all Orange*
s in a bucket.
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);
It is OK.
Now, I want Library::eatAll
to also support MyBinaryTree<Orange*>
, I have some not-so-desirable approaches as below.
My poor solution
1. Java way
- Make
MyBinaryTree<T>
andMyArray<Orange*>
(and their iterator) inherit from a new classCollection<T>
(andCollectionIterator<T>
). - change signature to
Library::eatAll(const Collection<T>&)
Disadvantage : performance penalty from "virtual" of some functions in Collection<T>
.
2. Template v1
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
orange->eaten();
}
}
- make
eatAll
a template function
Disadvantage : The implementation of the eatAll
must be in header.
I have to #include orange.h
in Library.h
.
Sometimes, I really want to just forward declaration.
3. Template 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();
}
- create a middle-man function
eatAnOrange
Disadvantage :
- Code is less readable, not concise, cause a little maintainability problem.
- If there are a lot of other functions e.g.
squeezeAll()
, I probably have to create a lot of middle-man functions, e.g.squeezeAnOrange()
.
4. Operator=()
Create converter among the 3 collection classes via implicit constructor.
Disadvantage : Suffer performance from creating a new instance of collection.
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
I believe my solutions are inelegant.
Are there any solutions that don't suffer the mentioned disadvantage?
Edit:
Both of current answers are elegant than my approaches (thank!), but still has disadvantage :-
- Oliv's requires #include "orange.h"
in User.h
.
- Richard Hodges's has virtual function calling.