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

我明白了,因为我将数组对象声明为 class 的对象Foo,所以myBar在该范围内引用的引用myBar将好像它是 aFoo并因此解释thisArray为等于 2 的大小。我也理解为什么ivar会这样。

有没有办法影响类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

很清楚我迟到了两年,我想添加另一个选项 - 对于那些在没有虚拟方法或新运算符的情况下寻求这个问题的答案的人:

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 回答