2

我正在将 zip 和 rar 档案中的文件提取到原始缓冲区中。我创建了以下内容来包装 minizip 和 unrarlib:

Archive.hpp - 用于访问所有内容。如果我可以让其他类中的所有功能都无法从外部访问,我会的。(实际上,我想我可以成为 Archive 中所有其他类的朋友,并使用私有函数回调......,但这太迂回了。)

#include "ArchiveBase.hpp"
#include "ArchiveDerived.hpp"
class Archive {
  public:
    Archive(string path) {
      /* logic here to determine type */
      switch(type) {
        case RAR:
          archive_ = new ArchiveRar(path);
          break;
        case ZIP:
          archive_ = new ArchiveZip(path);
          break;
        case UNKNOWN_ARCHIVE:
          throw;
          break;
      }
    }
    Archive(Archive& other) {
      archive_ = // how do I copy an abstract class?
    }
    ~Archive() { delete archive_; }
    void passThrough(ArchiveBase::Data& data) { archive_->passThrough(data); }
    Archive& operator = (Archive& other) {
      if (this == &other) return *this;
      ArchiveBase* newArchive = // can't instantiate....
      delete archive_;
      archive_ = newArchive;
      return *this;
    }
  private:
    ArchiveBase* archive_;
}

档案库.hpp

class ArchiveBase {
  public:
    // Is there any way to put this struct in Archive instead,
    //  so that outside classes instantiating one could use
    //  Archive::Data instead of ArchiveBase::Data?
    struct Data {
      int field;
    };
    virtual void passThrough(Data& data) = 0;
    /* more methods */
}

ArchiveDerived.hpp "Derived" 是 "Zip" 或 "Rar"

#include "ArchiveBase.hpp"
class ArchiveDerived : public ArchiveBase {
  public:
    ArchiveDerived(string path);
    void passThrough(ArchiveBase::Data& data);
  private:
    /* fields needed by minizip/unrarlib */
    // example zip:
    unzFile zipFile_;
    // example rar:
    RARHANDLE rarFile_;
}

ArchiveDerived.cpp

#include "ArchiveDerived.hpp"
ArchiveDerived::ArchiveDerived(string path) { //implement }
ArchiveDerived::passThrough(ArchiveBase::Data& data) { //implement }

有人建议我使用这种设计,以便我可以这样做:

Archive archiveFile(pathToZipOrRar);
archiveFile.passThrough(extractParams); // yay polymorphism!
  • 如何为存档编写 cctor?

  • 归档的 op= 怎么样?

  • 我能做些什么“重命名”ArchiveBase::DataArchive::Data?(minizip 和 unrarlib 都使用此类结构进行输入和输出。数据对于 Zip 和 Rar 是通用的,后来用于创建各自库的结构。)其他所有内容都通过 访问Archive,我想Data在外部类中声明这种方式也是如此。

我知道我可以将我的 current class Archive、 nameArchiveBase扔到Archive中,并使用全局工厂函数。但是,我想避免使用全局函数。

4

2 回答 2

3

首先,你不能“复制”一个抽象类,因为你不能实例化一个。相反,您应该做的是设置该类的 std::tr1::shared_ptr 并传入一个指针。

Archive(ArchiveBase *_archiveBase)

使用 Archive 类之外的工厂函数进行实例化。

Archive createArchive(string _path, int _type){
    switch(type) {
    case RAR:
      return Archive( new ArchiveRar(path) );
    case ZIP:
      return Archive( new ArchiveZip(path) );
    case UNKNOWN_ARCHIVE:
      throw exception("Unknown archive format");
      break;
    default:
      throw exception("Improper archive type");
  }

对于 = 运算符,只需持有这样的智能指针并使用“=”即可在类之间执行安全的知识传输。它执行引用计数并将删除指针,因此您不必并且仅在安全的情况下这样做。

Archive& operator = (Archive& other) {
  m_ArchiveBasePtr = other.m_ArchiveBasePtr;
  return *this;
}

让智能指针为您处理删除、复制等所有事情。

于 2010-03-29T01:41:35.737 回答
2

当你能负担得起浅拷贝和 N-1 关系时,Wheaties建议有效。当 ArchiveBase 子类包含每个 Archive 实例的特定一对一数据时,它就会崩溃,并且不会在多个对象之间正常共享。

全局 createArchive() 函数的另一种方法是将抽象虚拟 clone() 方法添加到 ArchiveBase,然后在每个子类(ArchiveZip、ArchiveRar)中定义它,以根据需要适当地复制浅拷贝或深拷贝。

然后,如果 archive_ 不为 NULL,您可以从 Archive 的复制构造函数或 operator= 调用 archive_.clone()。(请务必在之后删除(免费)它!)

关于将 ArchiveBase::Data “重命名”为 Archive::Data,我能做些什么?(minizip 和 unrarlib 都使用此类结构进行输入和输出。数据对于 Zip 和 Rar 是通用的,后来用于创建各自库的结构。)

有几种选择:

Archive::passThrough() { archive_ -> passThrough( this->getData() ) }
Archive::passThrough() { archive_ -> passThrough( this ) }

或者,您可以在 ArchiveBase 中维护对相应存档对象的向后引用,然后可以查询该对象以获取数据。

虽然使用小心!很容易让这些重复的信息不同步。(你可以进入头文件循环。)这就是为什么我喜欢传递this指针!你总是可以预先声明“class Archive;” 然后在头文件中不包含 Archive.hpp 的情况下使用 Archive* 指针。(尽管您仍然需要在 .cpp 文件中包含 Archive.hpp。)

于 2010-03-29T03:02:58.397 回答