2

zip および rar アーカイブから raw バッファーにファイルを抽出しています。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_;
}

ArchiveBase.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「派生」は「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::Dataへの「名前変更」について何ができArchive::Dataますか? (minizip と unrarlib の両方が入力と出力にこのような構造体を使用します。データは Zip と Rar では一般的であり、後でそれぞれのライブラリの構造体を作成するために使用されます。) 他のすべては 経由でアクセスされ、外部クラスでArchive宣言したいと思います。Dataこの道も。

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

Wheatiesの提案は、浅いコピーと N-1 の関係に余裕がある場合に有効です。ArchiveBase サブクラスに各アーカイブ インスタンスの特定の 1 対 1 のデータが含まれ、複数のオブジェクト間で適切に共有されない場合、これは機能しなくなります。

グローバルな createArchive() 関数の代替アプローチは、抽象的な仮想 clone() メソッドを ArchiveBase に追加し、それを各サブクラス (ArchiveZip、ArchiveRar) で定義して、必要に応じて浅いコピーまたは深いコピーを適切に複製することです。

その後、アーカイブのコピー コンストラクターから archive_.clone() を呼び出すか、archive_ が NULL でない場合は operator= を呼び出すことができます。(後で必ず削除(無料)してください!)

ArchiveBase::Data から Archive::Data への「名前変更」について何ができますか? (minizip と unrarlib の両方が、入力と出力にこのような構造体を使用します。データは Zip と Rar では一般的であり、後でそれぞれのライブラリの構造体を作成するために使用されます。)

いくつかのオプションがあります:

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

または、対応する Archive オブジェクトへの後方参照を ArchiveBase に維持し、Data に対してクエリを実行することもできます。

でも気をつけて!このような重複した情報は簡単に同期できなくなります。(そして、ヘッダー ファイルのループに入る可能性があります。) そのため、私はthisポインターを渡すことを好みます。「class Archive;」はいつでも事前宣言できます。次に、ヘッダー ファイルに Archive.hpp を含めずに Archive* ポインターを使用します。(ただし、.cpp ファイルに Archive.hpp を含める必要があります。)

于 2010-03-29T03:02:58.397 に答える