Say I have Archive interface and File interface.
- Each
Fileis guaranteed to have at leaststd::string name. - Each
Archivecanstd::vector<File*> Archive::list() constits files. - Each
ArchivecanArchive::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
ZipArchivecould 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_castthe 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 concreteZipArchiveimplementation can than check if its one of its files by a simple pointer comparsion.