2012-07-08 71 views
0

我有指针的容纳结构大量(如,几百)。每个指针都是不同的类型,但它们都从一个通用的基类继承而来 - 我们称之为Base。我正在使用多重继承。 (这是所有机器产生的,这就是为什么它的怪异。)C++:处理结构成员作为数组

例如为:

class Data { 
    Class1* p1; 
    Class2* p2; 
    Class3* p3; 
    ...etc... 
}; 

我想打电话给在基地上定义所有这些方法。我可以生成这样的代码:

void callFooOnData(Data* p) 
{ 
    if (p1) p1->Foo(); 
    if (p2) p2->Foo(); 
    if (p3) p3->Foo(); 
    ...etc... 
} 

的问题是,我有很多和很多的这些,一个十亿不同种类的数据,并在上面的代码最终被非常大,影响到我的足迹。所以我试图用更聪明的东西取代它。

在C,我可以简单地采取的第一个结构部件和计数的地址,这样做:

void callFooOnData(Data* p) 
{ 
    callFooOnObjects(&p1, 3); 
} 

但是,当然,我不能做这在C++,因为结构成员都没有一个统一的类型,并把它们铸造基地*可能涉及到更改它们,这可能涉及更改指针,因为他们没有一个统一的类型,指针会为每个成员进行不同的变化,我不能那样做。

有没有办法做这样的事情,这是C++?这是所有机器生成的代码,所以它不必非常漂亮,幸运的是---鲨鱼已经被跳过了---但我确实需要它尽可能便携......

(I有机会获得RTTI,但想如果可能的话,以避免由于性能原因)

更新:

所以,据我可以告诉...你就不能在做这个C++。根本无法完成。我被一个事实,即它是完全简单的C.在C++中,你可以在一个类层次结构只有安全将指针两种类型之间,如果你有一个良好类型的指针开始,当然,我没有误导。

所以我将不得不改变底层的问题,以避免这种情况:我提出的解决方案是将每个指针存储在结构中两次,一次存储在一个Base *数组中,用于迭代,以及一次作为ClassWhatever *用于调用方法。当然,这太糟糕了,因为它会增加数据结构的大小。

所以,如果有人想证实这一点(我喜欢被证明是错误的),我会高兴地纪念他们的答案是正确的......

+0

是否可以将所有指针设置为基本指针,还是有时必须调用仅为某些派生类型定义的方法?后者是 – 2012-07-08 18:28:40

+0

。每个成员都需要是适当的类型。 – 2012-07-08 19:07:59

回答

4

每个指针是不同类型的,但他们都继承从公共基类---我们称之为基础

而不必数百名成员的,只是不断的Base类指针容器:

class Data { 
    std::vector<Base*> objects; 
}; 

在一个好的设计中,你并不需要知道每个对象的类型,如果它被抽象出来,它实际上会更好。请记住,对接口进行编程总是很好,而不是具体的类。

,并将其铸造基地*可能涉及到更改他们

不是真的,对于public继承演员应该是隐含的。

如果你只对他们全部调用Foo()Foo()可以是基类中的virtual方法,那样你就可以充分利用多态性。

+0

+1 2秒打我.... – 2012-07-08 18:28:14

+0

他说的是生成的类机器,所以也许他不能令向量? – loganfsmyth 2012-07-08 18:28:43

+0

@loganfsmyth我错过了那部分......但是如果它是机器生成的,我没有看到问题的关键。我的意思是......代码就是这样。 – 2012-07-08 18:32:14

0

但是,当然,我不能这样做在C++中,因为结构成员 都没有一个统一的类型,并把它们铸造基地*可能涉及到更改 他们,这可能涉及改变指针,并且因为它们不是统一类型,所以每个成员都必须以不同的方式更改指针 ,我不能这样做。

虽然它是一个坏主意,这是不正确的: 您可以使用指针运算就像你在做C.在指针遍历指针都是一样的大小,他们有一个共同的基类(不考虑结构对准问题等)。它肮脏,但技术上它有效。如果你将这些实例本身作为类中的成员,而不是指向它们,那将是不同的。

在C++ 11,最好的办法是使用

std::vector< std::unique_ptr<Base> > objects; 

看到http://www.drdobbs.com/cpp/c11-uniqueptr/240002708

+0

这仅适用于线性继承情况下,如果你知道不同类型的指针指向同一个对象具有相同的值。当使用多重继承时,就像我一样,这不是真实的---在将Class1 *转换为Base *时,编译器会插入指令来更改指针。 – 2012-07-08 19:54:21

-1

所有指针具有相同的尺寸(在C中的所有类对象的指针++具有相同的尺寸),并在实践中,为了在这个指针列表中的任何位置插入填充,编译器需要相当不正确。无论如何,可能的填充问题与C中的相同。因此,您可以像C中那样完成相同的操作,完全没有问题。

void foo(Base const*); 

void bar() 
{ 
    // ... 
    foo(*(&thingy.p1 + 3)); 
} 

就这么简单。即使使用机器生成代码,设计听起来也很可怕,错误,真的很糟糕。

当生成vtables时(每个指针指向一个通常不同的签名的函数),其中一个会得到这样的东西,但它非常罕见。所以,这听起来像是一个XY问题。像,你’重新尝试解决问题X,已经想出了一个ungood解决方案Y,并且现在正在询问想象中的解决方案Y而不是真正的问题X&hellip;

+0

不行,恐怕---多重继承意味着很多有关指针的C假设都是无效的。 – 2012-07-08 19:56:18

+0

我第一次写了一条评论说你错了,但后来我意识到你总是可以让它不起作用。这与使其工作相反。我很愚蠢地回答你的问题,对不起。 – 2012-07-08 20:09:52

0

您必须通过自动生成您的代码来与自动生成的代码进行“斗争”。你可以使用像ctags这样的工具来“解析”你的自动生成的类并从ctags输出自动生成你的代码。请参阅http://ctags.sourceforge.net/ctags.html

您也可以尝试按照建议的方式将您的数据转换为元组,这可能是重复的,问题:Iterate through struct variables

我不知道这是更快...

如果可以修改工具,它会自动生成这个源代码 - 也许最好将扩展该工具...

0

另一种选择(不可编译):

class DataManipulator 
{ 
public: 
    DataManipulator(const Data& aData_in) 
    { 
     objects.add(aData_in->Class1); 
     . 
     . 
    } 
    void operate() 
    { 
     for(objects_iterator...) 
     { 
      if(*objects_iterator != NULL) 
       objects_iterator->Foo(); 
     } 
    } 
private: 

    std::vector<Base*> objects; 
}; 
0

我不想改变我以前的答案。但是我来到另一个解决方案,应该为你工作:完整的例子在这里:http://ideone.com/u22FO

主要部分如下:

struct C { 
    A1* p1; 
    A2* p2; 
    A3* p3; 
    A4* p4; 
    // ... 
}; 

template <class D, size_t startNumber, size_t numMembers, bool notFinished> 
struct FooCaller; 
template <class D, size_t startNumber> 
struct FooSingleCall; 

template <class D, size_t startNumber, size_t numMembers> 
struct FooCaller<D, startNumber, numMembers, false> { 
    void operator() (D& d) {} 
}; 

template <class D, size_t startNumber, size_t numMembers> 
struct FooCaller<D, startNumber, numMembers, true> { 
    void operator() (D& d) { 
     FooSingleCall<D,startNumber>()(d); 
     FooCaller<D, startNumber + 1, numMembers, startNumber < numMembers>()(d); 
    } 
}; 

#define FooSingleCallD(n) \ 
template <class D> \ 
struct FooSingleCall<D,n>{ \ 
    void operator() (D& d) { \ 
     d.p##n->foo(); \ 
    } \ 
} 

FooSingleCallD(1); 
FooSingleCallD(2); 
FooSingleCallD(3); 
FooSingleCallD(4); 
// ... unfortunately repeat as many times as needed 

template <class D, size_t numMembers> 
void callFoo(D& d) 
{ 
    FooCaller<D, 1, numMembers, 1 <= numMembers>()(d); 
} 

意识到:足够聪明,不定义成百上千FooSingleCall ...查看之一答案这个著名的问题:https://stackoverflow.com/a/4581720/1463922,你会看到如何让1000个实例,在短短5行...

另外,请与你的类的东西取回的N-取代指针FooSingleCall - 像GetNPointer ...