0

この質問は、「Thinking in C ++」Vol-1、第5章の演習No.14からのものです。

StackImpと呼ばれるクラスに要素を格納するために使用する低レベルのデータ構造を非表示にする「Cheshirecat」手法を使用して、StackOfIntクラス(intを保持するスタック)を作成します。StackImpの2つのバージョンを実装します。1つはintの固定長配列を使用し、もう1つはベクトルを使用します。スタックの最大サイズを事前に設定しておくと、最初のバージョンでアレイを拡張することを心配する必要がなくなります。StackOfInt.hクラスはStackImpで変更する必要がないことに注意してください。

これが私が作成したヘッダーファイル(StackOfInt.h)です:

#ifndef STACKOFINT_H
#define STACKOFINT_H

class StackOfInt
{
    int size;
    int curr_idx;
    class StackImp;
    StackImp* head;
  public:
    void initialize(int max);
    void push(void* dat);
    void* peek();
    void* pop();
    void cleanup();
};
#endif

ただし、実装に関しては、配列とベクトルの違いを処理する方法について混乱しています。これが私がこれまでに思いついたものです:

#include "StackOfInt.h"
#include "require.h"
#include <vector>

class StackOfInt::StackImp
{
    int arrInt[50];
  public:
    void initialize()
    {
        for (int i = 0; i < 50; i++)
        {
            arrInt[i] = 0;
        }
    }
};

/*
class StackOfInt::StackImp
{
    std::vector<int> vecInt;
}
*/

void StackOfInt::initialize(int max)
{
    size = max;
    curr_idx = 0;
    head = 0;
    StackImp* newImp = new StackImp;
    newImp->initialize();
}

void StackOfInt::push(void* dat)
{
    *(head+curr_idx) = dat;
    curr_idx++;
}

void* Stack::peek(int idx)
{
    require(head != 0, "Stack empty");
    return head[idx];
}

void Stack::cleanup()
{
    require(head == 0, "Stack not empty");
} ///:~

私は間違った方向に進んでいると思いますが、誰かがこの問題を解決する方法についていくつかのヒントを教えてもらえますか?

4

3 に答える 3

1

本の著者が念頭に置いているのは、StackOfIntクラスには、実装クラスへのポインター以外のメンバーを含めてはならないということです。必要なデータメンバーは、配列+カウント変数またはベクトルであり、実装クラスのメンバーである必要があります。

したがって、ヘッダーには次のようになります。

class StackOfInt {

    class StackImp;
    StackImp* impl;
public:
    void initialize();
    void push(int dat);
    int peek();
    int pop();
    void cleanup();
};

実装ファイルには、次の実装があります。

class StackOfInt::StackImp
{
public:
    int count;
    int array[100];
};

void StackOfInt::initialize()
{
    impl = new StackImp;
    impl->count = 0;
}

void StackOfInt::push(int dat)
{
    impl->array[impl->count++] = dat;
}

//and other methods

StackOfImpクラスを使用する別のcppファイルを作成します。プロジェクトをコンパイルしてプログラムを実行し、すべてが正常に機能することを確認します:)

これで、StackOfIntの実装ファイルを完全に書き直して、基になる型としてベクトルを使用できます。プロジェクトを再コンパイルします。StackOfImp(テストコード)のユーザーは、ヘッダーで何も変更されていないため、再コンパイルする必要がないことに注意してください。

著者が「チェシャ猫」と呼ぶテクニックについてもっと読むには:不透明なポインター


voidポインタの使い方がわかりません。StackOfIntは整数を受け取り、返す必要があります。

実装ポインタを呼び出すheadことも、いくつかの誤解を示しているようです。これは、スタックを実装するために必要なメンバーを実際に含むオブジェクトへのポインターを表します。

于 2011-03-23T20:17:16.183 に答える
0

これを処理する1つの方法は、「impl」クラスをポリモーフィックにし、ファクトリを使用して構築時に実装を選択することです。

于 2011-03-23T20:10:06.577 に答える
0

2つの別々のcppファイルに2つの異なる実装があり、それを使用するためにプロジェクトにどちらか一方を含めることが期待されていると思います。

StackImplArr.cpp

     class StackOfInt::StackImp
     {
       int arrInt[50];
     }

StackImplVec.cpp

     class StackOfInt::StackImp
     {
       std::vector<int> vecInt;
     }

より高度な使用法では、基本クラスを宣言し、そこから2つの実装を派生させて、実行時に実装を選択できるようにします。

     class StackOfInt::StackImp
     {
       virtual initialize() = 0;
     }

     class StackOfInt::StackImpArr : public StackOfInt::StackImp
     {
       int arrInt[50];
       virtual initialize() { ... }
     }

     class StackOfInt::StackImpVec : public StackOfInt::StackImp
     {
       std::vector<int> vecInt;
       virtual initialize() { ... }
     }

     void
     StackOfInt::initialize( int max) {
       head = condition ? new StackImpArr() : new StackImpVec();
     }
于 2011-03-23T20:16:47.693 に答える