有没有办法在继承类的基类中指定数组的大小?

时间:2013-10-26 20:05:30

标签: c++ templates inheritance

我有一个抽象基类,它包含一个数组以及两个或多个继承类,它们希望在基类中有一个稍大的数组。

我尝试使用模板来解决这个问题:

template <int arraySize>
class Baseclass {
public:
    uint16_t arr[arraySize];
};

class InheritedClass :
    public Baseclass <5> {};

我现在面临的问题是: 每当我使用指向某个Baseclass-Object的指针时,编译器就会抱怨:

  

类模板的参数列表“Baseclass”缺失

我想我理解这里发生了什么:没有模板参数的Baseclass现在不是一个完整的类型 - 但编译器需要一个。

因此我想知道 - 是否有一种(更好的)方法来实现我想要做的事情,而不是在InheritedClass中分配数组并将指针传递给Baseclass?

提前谢谢!

5 个答案:

答案 0 :(得分:3)

如果数组直接嵌入到基类中(如示例中所示),则无法指定该数组的大小。更确切地说,更改该数组的大小将需要为每个特定的数组大小生成完全不同的基类版本。这将破坏目的,因为您的意图显然是在层次结构中具有单个公共基类。是吗?

这正是您遇到模板“解决方案”时遇到的问题。您的程序不再具有通用Baseclass。相反,你有Baseclass<5>Baseclass<10>等等 - 所有完全不同的独立基类。显然,这不是你所需要的。

实现具有运行时大小数组的公共基类的唯一方法是将数组存储在基类间接中。即在基类中声明一个uint16_t *指针,并在运行时分配适当的内存量。或者您只需使用std::vector<uint16_t>而不是原始数组。

请注意,如果您决定使用指针方式,则不一定要动态分配数组内存。您可以简单地将实际的“数组内存”作为已知“已知”特定大小的派生类的成员

class Baseclass {
public:
  uint16_t *arr;
  size_t arraySize;

  Baseclass(uint16_t *arr, size_t arraySize) : arr(arr), arraySize(arraySize)
    {}
};

class InheritedClass : public Baseclass
{
  InheritedClass() : Baseclass(arr_memory, 5)
    {}
private:
  uint16_t arr_memory[5];
};

所以,最重要的是,如果您希望将数组内存管理完全封装到Baseclass中,那么除了在运行时动态分配内存之外别无选择。如果这是不可接受的,那么您只能在其他地方执行内存管理并从外部将其传递给Baseclass

答案 1 :(得分:1)

您可以从非模板类派生Baseclass,并使用指向该模板的指针。

答案 2 :(得分:0)

class Baseclass {
public:
    uint16_t *arr;
    Baseclass(int arrlen) {
        arr = new int[arrlen];
    }

    ~Baseclass() {
        delete arr;
    }

};

class InheritedClass :
    public Baseclass {
public:
    Inherited() : Baseclass(5){
    }
};

如果可以,您可以简单地使用动态分配。

答案 3 :(得分:0)

作为可能有用的黑客,请在baseclass reinterpret_cast this baseclass<1>中添加baseclass方法。

这依赖于你的ty0es被编译成相对理智的布局:为了鼓励这种情况发生,确保baseclass至少是pod或标准布局。

虽然结果是未定义的行为,但在我使用的每个编译器中都可以使用它。

缺点?您的数组必须并行传输多大,并且您可以向类的其他用户说明运行时数组的大小。此外,它非常脆弱:数组必须是std::vector的最后一个元素。

最好不要使用编译时静态边界,并存储带有运行时边界的{{1}},因为这样可以避免未定义的行为破坏并减少每行代码的谎言。

答案 4 :(得分:0)

如果明确指定参数,C ++将忽略默认表达式。因此,在派生类中,您可以明确指定CRTP'd base的需求,但在基础中,您还提供了一个默认值计算,仅在实例化后使用(仅)。 所以:

#include <iostream>
// instantiation specifies size explicitly, default calculation ignored
// after instantiation names in default calculation are bound correctly

template<class d,int size=sizeof d::m2/sizeof *d::m2>
struct b {
        int m[size];
};

struct d: b<d,20> {
        double m2[20];
};

int main() {
        std::cout<<sizeof b<d>::m/sizeof *b<d>::m<<'\n';
}