我有一个多个类继承的接口。
class someInterface
{
virtual void someMethod() = 0;
}
class A : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class B : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
class C : public someInterface
{
public:
void someMethod()
{
//Do something
}
}
对于A,B,C类中的每一个,我在容器类中创建了一个具有不同大小的实际类型的数组。
class AContainer
{
public:
A As[10];
}
class BContainer
{
public:
B Bs[5];
}
etc...
此外我有一个指向" SomeInterface"的指针数组,其中我希望有一个指向每个实际数组的指针。
#define SOMEINTERRFACE_SIZE 3
someInterface *array[SOMEINTERRFACE_SIZE];
array[0] = AContainer.As; //Could also just be &AContainer.As[0]
array[1] = BContainer.Bs;
array[2] = CContainer.Cs;
for (int i = 0; i < SOMEINTERRFACE_SIZE; ++i)
{
int elements = //Here i need a solution to get the size
//So i can iterate through the array, which the pointer points to.
for (int i = 0; i < elements; ++i)
{
//Call the interface method on each element.
}
}
当我必须使用someInterface数组时会出现问题,因为不可能通过someInterface指针获取实际数组的大小。
这个问题的解决方案是什么?我真的需要一些帮助来解决这个问题。 也不想使用动态分配,因此没有带矢量的解决方案&lt;&gt;或者malloc等因为我写信给Arduino。
答案 0 :(得分:1)
它不会起作用。在C ++中,您必须知道数组中元素的大小。 A
,B
和C
的大小可能不同,因此您无法对它们的数组进行相同的处理。
&AContainer.As[i] == &AContainer.As + i * sizeof(A)
但
&BContainer.Bs[i] == &BContainer.Bs + i * sizeof(B)
因此,相同的机器代码无法迭代A
和B
的数组。如果要迭代一组对象,则需要知道确切的类型。
请记住,在C ++中,如果要获得多态虚拟调用,则需要通过指针或引用。解决方案是将指针复制到每个数组中的元素到一个&#34; master&#34;阵列。
SomeInterface *ptrs[NUM_A + NUM_B + NUM_C];
SomeInterface **dest = ptrs;
for (int i = 0; i < NUM_A; ++i) {
*dest++ = &AContainer.As[i];
}
for (int i = 0; i < NUM_B; ++i) {
*dest++ = &BContainer.Bs[i];
}
// et cetera...
这只占用了一点额外的空间,因为你要存储指针,而不是实际的对象。
编辑:如果你真的想节省空间,我想你可以做这样的事情:
someInterface *arrays[] = { AContainer.As, BContainer.Bs, CContainer.Cs };
int objSizes[] = { sizeof(A), sizeof(B), sizeof(C) };
int arrLengths[] = { NUM_A, NUM_B, NUM_C };
for (int j = 0; j < sizeof(arrays)/sizeof(arrays[0]); ++j)
{
void *ptr = arrays[j];
for (int i = 0; i < arrLengths[j]; ++i) {
someInterface *iptr = (someInterface *)ptr;
iptr->method();
ptr += objSizes[j];
}
}
(这是未经测试的,你可能需要调整一下。)
理论上,由于所有这些数组都充满了编译时常量,因此它应该快速优化。如果它没有,代码将运行得更慢,因为它将通过仅在运行时而不是编译时知道的值递增指针。如果你真的关心速度,你应该检查装配输出。
答案 1 :(得分:0)
如果不了解应用程序的更多细节,很难回答 - 但这里有一些可能有用的想法。
假设:
class someInterface { public: virtual char someMethod() = 0; };
class A : public someInterface { public: char someMethod() { return 'A'; } };
class B : public someInterface { public: char someMethod() { return 'B'; } };
class C : public someInterface { public: char someMethod() { return 'C'; } };
你可以手动滚动这样的东西:
class Array {
public:
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < countA ; ++i) function(As[i]);
for (size_t i = 0 ; i < countB ; ++i) function(Bs[i]);
for (size_t i = 0 ; i < countC ; ++i) function(Cs[i]);
}
private:
enum {countA = 10, countB = 5, countC = 3};
A As[countA];
B Bs[countB];
C Cs[countC];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array array;
array.forEach(doSomeMethod);
return 0;
}
请注意,通过使用“回调”函数doSomeMethod
,我们可以解决在多态集合中调度的典型问题。
当然,你不想保持这样的手卷。实际上我检查的Arduino C ++编译器有模板支持,所以你可以做类似的事情:
template <class T, size_t _size, class NextArray = void>
struct Array {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
nextArray.forEach(function);
}
private:
T elements[_size];
NextArray nextArray;
};
template <class T, size_t _size>
struct Array<T, _size, void> {
public:
typedef T value_type;
enum {size = _size};
void forEach( void(*function)(someInterface&) ) {
for (size_t i = 0 ; i < _size ; ++i)
function(elements[i]);
}
private:
T elements[_size];
};
void doSomeMethod(someInterface& element) {
std::cout << element.someMethod();
}
int main(int, char**) {
Array<A, 10, Array<B, 5, Array<C, 3> > > array;
array.forEach(doSomeMethod);
return 0;
}
让编译器为您编写类型和大小的不同组合。一些值得注意的事情:
如果你不能使用回调方法(并且你的编译器还不支持lambdas),那么你可以尝试下一个选项,这会比上面给出的选项产生一些小的运行时成本:
template <class Interface>
class ArrayInterface {
public:
virtual size_t getSize() = 0;
virtual Interface& getElement(size_t index) = 0;
};
template <class T, class Interface, size_t size>
class Array : public ArrayInterface<Interface> {
public:
size_t getSize() { return size; }
Interface& getElement(size_t index) { return element[index]; }
private:
T element[size];
};
int main(int, char**) {
Array<A, SomeInterface, 10> As;
Array<B, SomeInterface, 5> Bs;
Array<C, SomeInterface, 3> Cs;
const int SOMEINTERRFACE_SIZE = 3;
ArrayInterface<SomeInterface>* array[SOMEINTERRFACE_SIZE] = {&As, &Bs, &Cs};
for (size_t i = 0 ; i < SOMEINTERRFACE_SIZE ; ++i) {
ArrayInterface<SomeInterface>& innerArray = *array[i];
for (size_t j = 0 ; j < innerArray.getSize() ; ++j)
std::cout << innerArray.getElement(j).someMethod();
}
return 0;
}
(最后一个使用指针的外部数组,根据您的问题)
这篇文章已经太长了,所以我没有详细介绍,或者深入研究选项,例如单个,平面的成员函数指针数组。如果您有任何疑问,请大声喊叫。
答案 2 :(得分:-1)
这是你想要实现的目标吗? 迭代一个对象列表并调用一个公共接口的重新实现方法?
将这段代码放在全局C ++范围内的任何地方进行测试。
#include <vector>
#include <iostream>
int TestSomewhereInCppGlobalScopeCode()
{
class someInterface
{
public:
virtual void someMethod() = 0;
};
class A : public someInterface
{
public:
void someMethod()
{
std::cout << "A::someMethod()";
}
};
class B : public someInterface
{
public:
void someMethod()
{
std::cout << "B::someMethod()";
}
};
class C : public someInterface
{
public:
void someMethod()
{
std::cout << "C::someMethod()";
}
};
std::vector<someInterface*> ListOfObjectsHavingCommonInterface;
ListOfObjectsHavingCommonInterface.push_back( new A );
ListOfObjectsHavingCommonInterface.push_back( new B );
ListOfObjectsHavingCommonInterface.push_back( new C );
for ( std::vector<someInterface*>::iterator it = ListOfObjectsHavingCommonInterface.begin();
it != ListOfObjectsHavingCommonInterface.end();
++it )
{
(*it)->someMethod();
}
return 0;
}
static int TestSomewhereInCppGlobalScopeCode_Caller = TestSomewhereInCppGlobalScopeCode();