C ++是否支持抽象数组长度

时间:2016-04-14 19:22:53

标签: c++ arrays inheritance

如果我有基类A,我希望能够在A中编写代码,该代码使用的数组大小由其子代决定

我希望能够有一个指向A的指针数组,但我不希望为每个长度创建一个单独的成员函数

我能想出的最好成绩如下:

class A
{
   char type;
   int * values;
   int calc(int pos);  // implementation is not relevant to question
public:
   A (int * arr) : values(arr) {}
   int foo(int pos)
   {
      int index=calc(pos);
      return values[index];
   }
};

template <size_t X>
class B : public A
{
    int vals[X];
public:
    B() : A(vals) {}
};

template<>
class B<0>;  // don't want 0 allowed

这允许A访问子节点确定大小的数组,并且它是连续的内存

但是,它浪费了values指针的空间并混淆了编译器可用于优化的信息,因为实现它不必是孩子在构造上传递的连续内存,但我想需要连续记忆。

理想情况下,我想直接在A

中使用偏移量

C中,这可用作int values[],但没有C++等效

3 个答案:

答案 0 :(得分:3)

是的,您可以使用模板:

template<std::size_t size>
struct A {
    A(std::array<int, size> _values) : values{_values} {}

private:
    std::array<int, size> values;
};

struct B : A<4> {
    using A<4>::A;
};

然后,您可以像这样使用您的课程:

B myB{5, 6, 3, 2};

std::array直接在堆栈或结构中分配内存,就像固定数组一样。您可以通过比较尺寸进行测试。

如果您需要一个共同的基类,您可以这样做:

struct C {
    virtual ~C() {}
    virtual int* data();
    virtual std::size_t size();
};

然后在A中重写论文:

template<std::size_t size>
struct A : C {
    A(std::array<int, size> _values) : values{_values} {}

    int* data() override {
        return values.data();
    }

    std::size_t size() override {
        return size;
    }

private:
    std::array<int, size> values;
};

答案 1 :(得分:2)

实现此目的的经典方法是使用继承和虚拟成员

class A {
    virtual int& value_at(size_t pos);
    // other interesting methods
};

// subclass of A that uses std::vector for storage
class B: public A {
    std::vector<int> storage;
    int& value_at(size_t pos) {
        return storage[pos];
    }
};

// subclass of A that uses a fixed-size array for storage
template<int N>
class C: public A {
    int storage[N];
    int& value_at(size_t pos) {
        return storage[pos];
    }
};

B b;     // ...initialize b...
C<10> c; // ...initialize c...
A *a1 = &b;
A *a2 = &c;
// call a1->value_at(), a2->value_at() to access arrays
// transparently, regardless of storage (along with other
// public methods of A).

此方法需要A::value_at通过虚拟表或等效机制进行调度。如果在编译时知道将使用哪种存储策略,则可以使A成为模板类:

template<typename T>
class A: public T {
    // other interesting methods, that use value_at() from T
};

class vec_storage {
    std::vector<int> storage;
public:
    int& value_at(size_t pos) {
        return storage[pos];
    }
};

// subclass of A that uses a fixed-size array for storage
template<int N>
class array_storage {
    int storage[N];
public:
    int& value_at(size_t pos) {
        return storage[pos];
    }
};

A<vec_storage> b;
A<array_storage<10>> c;

在此示例中,bc将在运行时没有额外的间接执行,但代价是没有通用基类,因此函数需要一些{{1} }无法传递对A &b的引用。

答案 2 :(得分:-2)

正如Fred Larson指出的那样,对于改变对象数组大小的基本能力,你可能正在寻找 templates 。这其实很简单......

template <const int arraySize>
class MyClass
{
    private:
        int vals[arraySize];
}

此时,您甚至不需要任何派生类。你很高兴,可以随时使用任意大小

但请记住,MyClass在此方案中不是有效类型。因为这是一个模板,所以必须指定大小。

MyClass wrong; //This will throw an error. MyClass is not a type.
MyClass<64> right; //This is a proper use of the type.

如果您需要额外的功能来存储不同大小的对象,您可以使用虚拟[但非抽象]基类轻松地将其与继承相结合。

(请忽略狡猾的设计,因为在这个例子中我没有打算定义我的构造函数/析构函数。)

class BaseClass
{
    public:
        BaseClass(){}
        virtual int access(int i)
        {
            return 0;
        }
        virtual ~BaseClass(){}
};

template <const int arraySize>
class MyClass : public BaseClass
{
    public:
        MyClass(){}
        int access(int i)
        {
            return vals[i];
        }
        ~MyClass(){}
    private:
        int vals[arraySize];
};
  

警告:如果您希望能够将派生类存储在向量中,则基本不是抽象的。请参阅this question

在本例中,您当然可能需要创建用于访问数组的包装函数。