Say I have Archive
interface and File
interface.
- Each
File
is guaranteed to have at leaststd::string name
. - Each
Archive
canstd::vector<File*> Archive::list() const
its files. - Each
Archive
canArchive::extract(std::vector<File*> files)
.
Then I have ZipArchive
and ZipFile
, ZipFile
contains offset in the archive file and other implementation details. Then there's TarArchive
/TarFile
and so on. Each of these fills std::vector<File*> list() const
with instances of ZipFile
, TarFile
etc.
list()
is meant to give users a chance to select which files to unpack. They select elements from that vector, then they pass this vector to extract()
.
At this point, the ZipArchive
needs to assume it was passed the right type and do dynamic_cast<ZipFile*>(file)
to access implementation details.
This feels bad. Is this acceptable? Are there alternatives?
Your
ZipArchive
could search in its list of files for the passed pointer. If it's in there, it could either use the stored pointer (which already is of typeZipFile
) orstatic_cast
the passed pointer toZipFile
(because you have proven its type). If the passed pointer is not in the list, it's obviously not a file owned by this archive, so you can go on with error handling.You could also add a backpointer of type
Archive*
to everyFile
. The concreteZipArchive
implementation can than check if its one of its files by a simple pointer comparsion.