2

クラスのメンバーとして配列があります。サブクラスで、配列を別のサイズで再定義したいと思います。多くのサブクラスを作成し、それぞれに必要な配列サイズのみを追加し、それ以上は作成しないと予想しているため、これを実行したいと思います。

class Foo
{
    Foo() {ivar = 1};
    int thisArray[2];
    int ivar;
}

class Bar : public Foo
{
    Bar() {ivar = 3};
    int thisArray[4];
}

int main()
{
    Foo myFoo;
    Bar myBar;

    Foo fooCollection[] = {myFoo,myBar};

    cout << "myFoo array size = " << sizeof(myFoo.thisArray)/sizeof(int) << endl;
    cout << "myBar array size = " << sizeof(myBar.thisArray)/sizeof(int) << endl;

    for (int n=0;n<2;n++)
    {
        cout << "fooCollection[" << n << "] array size = ";
        cout << sizeof(fooCollection[n].thisArray)/sizeof(int) << endl;
    }
    for (int n=0;n<2;n++)
    {
        cout << "fooCollection[" << n << "] ivar = ";
        cout << fooCollection[n].ivar << endl;
    }

}

私の結果は次のとおりです。

myFoo array size = 2
myBar array size = 4
fooCollection[0] array size = 2
fooCollection[1] array size = 2
fooCollection[0] ivar = 1
fooCollection[1] ivar = 3

配列オブジェクトをクラスのオブジェクトとして宣言しているので、そのスコープ内で参照Fooすると、それがaであるかのように参照され、その結果、のサイズが2に等しいと解釈されます。myBarmyBarFoothisArrayivar

thisArrayクラス内のサイズに影響を与えて、その「正しい」サイズをオブジェクトBarの配列内で認識できるようにする方法はありますか?Fooベクトルを使用しますが、arduinoプラットフォームでは使い勝手が良くありません。Fooクラス内にサイズ100の配列を作成することもできますが、メモリの割り当てを意識しようとしています。

4

5 に答える 5

9

基本クラスをテンプレート化できます。

template <size_t Size>
class FooBase
{
    // etc....
    int thisArray[Size];
};

class Foo : public FooBase<2> { ... };

class Bar : public FooBase<4> { ... };

もちろん、これはすべてが派生する場合にのみ実用的FooBaseです。つまり、派生するクラスがなく、そこからBar異なる配列サイズが必要になります。

また、コメントで述べられているように、これらを配列に保持する必要がある場合は、ポインターを格納する必要があります。

Foo myFoo;
Bar myBar;
Foo * fooCollection[] = { &myFoo, &myBar };

Barおっと、私はそれがから派生していると仮定しましたFooが、それはもはやありません。テンプレート化されていない共通ベースが必要な場合は、テンプレート化されたクラスFooBase<Size>を別のベースから派生させFooType、の配列を使用する必要がありFooTypeます。私はそれがうまくいくと思います。

class FooType {
  public:
      // etc...
      virtual size_t GetSize() const = 0;
};

template <size_t Size>
class FooBase : public FooType
{
  public:
    // etc...
    virtual size_t GetSize() const { return Size; }

  protected:
    // etc....
    int thisArray[Size];
};

その後:

FooType *fooCollection[] = { &myFoo, &myBar };
于 2013-01-21T21:11:29.050 に答える
4

配列をポインターとして定義newしてから、コンストラクターとdeleteデストラクタで配列を定義できます。三つのルールを覚えておけば大丈夫です。

これは、私がこのプログラムの意図を完全に誤解していない限りです。

于 2013-01-21T21:06:57.417 に答える
2

これを行うと、実際のポリモーフィズムを使用していないためcout << sizeof(fooCollection[n].thisArray)/sizeof(int) << endl;、サイズを知ることはできません。thisArrayしたがって、コンパイラーは、のすべての要素fooCollectionが単純Foo(静的バインディング)であると想定します。

ポインタを使用して開始します。

Foo * fooCollection[] = { &myFoo, &myBar };

そして、実行時に配列のサイズを知る仮想メンバーを宣言します。(動的バインディング)

virtual int size() {return sizeof(thisArray);}

そして、次のように書き直します。

cout << fooCollection[n]->size()/sizeof(int) << endl;
于 2013-01-21T21:17:19.877 に答える
1

私の意見は、基本クラスを具体的なクラスにしないことです。

  1. 基本クラスを、配列へのインターフェイス(配列のサイズ、配列の読み取りと書き込み)を提供する抽象クラスとします。

  2. 配列の構築と破棄は、派生クラスによって制御されます。

このようにして、各派生クラスはその配列の長さを適切に選択できます。

コードスケッチ:

class foo {
  public:
    virtual size_t array_size() const = 0;
    virtual int *  array_base() const = 0;
    int array_get( size_t index ) const {
      array_verify_index( index );
      return *( array_base() + index );
    }
    void array_set( size_t index, int value ) {
      array_verify_index( index );
      *( array_base() + index ) = value;
    }
  private:
    void array_verify_index( size_t index ) const {
      assert( index < array_size() );
    }
};

class bar : public foo {
  public:    
    bar() {
       array_base = new int[ BarArraySize ];
    }
    ~bar() {
      delete [] array_base;
    }
    virtual size_t array_size() const {
      return BarArraySize;
    }
    virtual int * array_base() const {
      return array_base;
    }
  private:
    int * array_base;
};
于 2013-01-21T21:21:13.597 に答える
0

私は2年遅れていることをよく知っています。仮想メソッドや新しい演算子を使用せずにこの質問への回答を求める人のために、別のオプションを追加したいと思います。

class Foo
{
protected:
    // Can only be constructed by Bar, or other derived type.
    Foo(int* _array, size_t _size) :
        array(_array), 
        arraySize(_size)
    {};
private:
    int* array;
    size_t arraySize;
};

template<size_t Size>
class Bar : public Foo
{
public:
    Bar() : Foo(arrayData, Size) {};
private:
    int arrayData[Size];
};

これにより、Fooは、仮想メソッドがなく、スタックに配列が割り当てられた、いくつかのクラスの共通の「配列」インターフェイスになります。唯一の本当の欠点は、必然的にFoo :: arraySizeを挿入したことですが、それでも比較的低コストです(32/64ビットで4/8バイト)。

于 2017-08-10T13:15:06.493 に答える