覆盖子类中的数组大小

时间:2013-01-21 21:04:18

标签: c++ arrays inheritance

我有一个数组作为类的成员。在子类中,我想重新定义具有不同大小的数组。我想这样做是因为我期望制作许多子类,每个子类只需要它所需的数组大小,仅此而已。

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的对象,引用该范围内的myBar将引用myBar,就像它是Foo一样并因此将thisArray的大小解释为等同于2.我也理解为什么ivar以它的方式出现。

是否有办法影响thisArray类中Bar的大小,以便在Foo个对象的数组中识别其“正确”大小?我会使用矢量,但他们在arduino平台上并不友好。我也可以简单地在Foo类中创建大小为100的数组,但我试图意识到内存分配。

5 个答案:

答案 0 :(得分:8)

您可以模拟基类:

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 };

然后:

{{1}}

答案 1 :(得分:4)

您可以将数组定义为指针,然后使用构造函数new将其定义为析构函数中的delete。记住三法则,你会没事的。

这是除非我完全误解了你对这个程序的意图。

答案 2 :(得分: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;

答案 3 :(得分:1)

我的意见是不允许基类成为具体的类:

  1. 让基类成为提供接口的抽象类 数组(数组的大小,对数组的读写)。

  2. 让阵列的构造和破坏受到控制 派生类。

  3. 这样,每个派生类都可以根据需要选择其数组的长度。

    代码草图:

    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;
    };
    

答案 4 :(得分: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字节)。