C++:将结构成员视为数组
C++: treating structure members as an array
我有一个包含许多(比如数百个)指针的结构。每个指针都是不同的类型,但它们都继承自一个公共基类——让我们称之为base。我正在使用多重继承。(这都是机器生成的,这就是为什么它很奇怪。)
例如:
class Data {
Class1* p1;
Class2* p2;
Class3* p3;
...etc...
};
我想调用在Base中基于所有这些定义的方法。我可以生成这样的代码:
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++中做到这一点,因为结构成员不是统一的类型,将它们强制转换为Base*可能需要更改它们,这可能需要更改指针,因为它们不是统一类型,所以每个成员的指针都必须以不同的方式更改,我不能这样做。
有没有一种方法可以用C++来做这样的事情?这都是机器生成的代码,所以它不一定很漂亮,谢天谢地——鲨鱼已经被跳过了——但我确实需要它尽可能便携。。。
(我确实可以访问RTTI,但出于性能原因,如果可能的话,我想避免它。)
更新:
所以,据我所知。。。你在C++中无法做到这一点。根本做不到。我被一个事实误导了,那就是它在C中是完全直接的。在C++中,只有当你有一个类型良好的指针开始时,你才能在类层次结构中的两个类型之间安全地投射一个指针,当然,我没有。
因此,我必须改变潜在的问题来避免这种情况:我提出的解决方案是将每个指针存储在结构中两次,一次存储在Base*数组中用于迭代,另一次存储为ClassWhatever*用于调用方法。当然,这很糟糕,因为它会使数据结构的大小翻倍。
因此,如果有人想证实这一点(我希望被证明是错的),我会很高兴地将他们的答案标记为正确的。。。
每个指针都是不同的类型,但它们都继承自一个公共基类——让我们称之为Base
与其拥有数百个成员,不如保留一个Base
类指针的容器:
class Data {
std::vector<Base*> objects;
};
在一个好的设计中,你不需要知道每个对象的类型,如果把它抽象掉会更好。记住,针对接口而不是具体类进行编程总是很好的。
将它们铸造到基地*可能需要将其更改为
不是这样,对于public
继承,强制转换应该是隐式的。
如果只对所有方法调用Foo()
,那么Foo()
可以是基类中的virtual
方法,这样就可以充分利用多态性。
但是,当然,我不能在C++中做到这一点,因为结构成员不是统一的类型,将它们铸造到Base*可能需要更改它们,这可能涉及到更改指针,并且因为它们不是一个统一的类型,指针必须以不同的方式更改每个成员,我不能那样做。
尽管这是个坏主意,但事实并非如此:您可以像在C中那样使用指针算术来迭代指针。指针大小都相同,并且它们有一个公共基类(不考虑结构对齐问题等)。它很脏,但从技术上讲它是有效的。如果您将实例本身作为类中的成员而不是指向它们的指针,则情况会有所不同。
C++11中最好的方法是使用
std::vector< std::unique_ptr<Base> > objects;
参见http://www.drdobbs.com/cpp/c11-uniqueptr/240002708
您必须通过自动生成代码来"对抗"自动生成的代码。您可以使用ctags之类的工具来"解析"自动生成的类,并从ctags输出中自动生成代码。看见http://ctags.sourceforge.net/ctags.html.
您也可以尝试将数据强制转换为元组,如以下可能重复的问题所建议的:遍历结构变量。
我不确定哪个更快。。。
如果你能修改自动生成这个源代码的工具,也许最好的办法是扩展这个工具。。。
另一个选项(不可编译):
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;
};
我不想更改以前的答案。然而,我找到了另一个应该对您有效的解决方案:这里的完整示例: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);
}
Aware:足够聪明,不要定义数百个FooSingleCall。。。看看这个著名问题的答案之一:https://stackoverflow.com/a/4581720/1463922您将看到如何在5行中创建1000个实例。。。
此外,请将FooSingleCall替换为从类中检索N指针的东西——比如GetNPointer。。。
所有指针大小相同(C++中的所有类对象指针大小相同),在实践中,编译器需要非常反常才能在指针列表中的任何位置插入填充。无论如何,可能的填充问题和C中的一样。所以你可以做和C中一样的事情,一点问题都没有。
void foo( Base const* );
void bar()
{
// ...
foo( *(&thingy.p1 + 3) );
}
就这么简单。
也就是说,即使使用机器生成的代码,设计听起来也很可怕、错误、非常糟糕。
在生成vtables(每个指针指向一个签名通常不同的函数)时,确实有这种情况,但这种情况非常罕见。这听起来像是一个XY问题。比如,您;你试图解决问题X,提出了一个不好的解决方案Y,现在问的是想象中的解决方案,而不是真正的问题X…
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 为什么静态数组成员变量在调用对象的实例后不显示任何内容?
- C++ - 移动具有固定大小的 c 样式数组成员的类的构造函数
- C++内联数组成员统一初始化
- 有没有办法把字符串数组成员放在".structurevariable"前面?
- 将初始化列表传递给 C++ 中的数组成员
- 具有灵活数组成员的结构的大小
- 初始化固定的 C 数组成员结构
- 带有布尔数组成员的 C++ 结构.如何在主代码中使用
- 我如何通过构造函数大小私人std ::数组成员
- 通过两个下标访问数组成员
- size_t结构非数组成员崩溃的强制转换
- 删除数组成员的更好方法是什么?
- 从C 到C#调用INT []显示随机大数字,而不是原始数组成员
- 在C 中的数组初始化期间使用数组成员
- 友元函数将内存分配给数组成员是否有任何限制?
- 从结构传递数组成员会导致访问读取冲突
- 为什么 const char 数组成员的初始化在构造函数初始值设定项中不兼容
- 如何在 lambda 中访问数组成员
- 将整数值分配为variadic模板列表到静态const std ::数组成员