如果我有基类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++
等效
答案 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;
在此示例中,b
和c
将在运行时没有额外的间接执行,但代价是没有通用基类,因此函数需要一些{{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。
在本例中,您当然可能需要创建用于访问数组的包装函数。