【发布时间】:2015-05-12 21:25:31
【问题描述】:
在复杂的代码库中,我有一个非虚拟基类指针数组(基类没有虚拟方法)
考虑这段代码:
#include <iostream>
using namespace std;
class TBase
{
public:
TBase(int i = 0) : m_iData(i) {}
~TBase(void) {}
void Print(void) {std::cout << "Data = " << m_iData << std::endl;}
protected:
int m_iData;
};
class TStaticDerived : public TBase
{
public:
TStaticDerived(void) : TBase(1) {}
~TStaticDerived(void) {}
};
class TVirtualDerived : public TBase
{
public:
TVirtualDerived(void) : TBase(2) {}
virtual ~TVirtualDerived(void) {} //will force the creation of a VTABLE
};
void PrintType(TBase *pBase)
{
pBase->Print();
}
void PrintType(void** pArray, size_t iSize)
{
for(size_t i = 0; i < iSize; i++)
{
TBase *pBase = (TBase*) pArray[i];
pBase->Print();
}
}
int main()
{
TBase b(0);
TStaticDerived sd;
TVirtualDerived vd;
PrintType(&b);
PrintType(&sd);
PrintType(&vd); //OK
void* vArray[3];
vArray[0] = &b;
vArray[1] = &sd;
vArray[2] = &vd; //VTABLE not taken into account -> pointer not OK
PrintType(vArray, 3);
return 0;
}
输出为(在 Win64 上使用 Mingw-w64 GCC 4.9.2 编译):
Data = 0
Data = 1
Data = 2
Data = 0
Data = 1
Data = 4771632
失败的原因是TVirtualDerived的每个实例都有一个指向虚拟表的指针,而TBase没有。因此,在没有先前类型信息的情况下向上转换到 TBase(从 void* 到 TBase*)是不安全的。
问题是我一开始就无法避免强制转换为 void*。 在基类上添加一个虚拟方法(例如析构函数)是可行的,但会消耗内存(我想避免)
上下文:
我们正在一个非常受限的环境(内存严重受限)中实现一个信号/插槽系统。由于我们有数百万个可以发送或接收信号的对象,因此这种优化是有效的(当然,当它起作用时)
问题:
我该如何解决这个问题?到目前为止,我发现:
1 - 在 TBase 中添加一个虚拟方法。有效,但它并没有真正解决问题,它避免了它。而且效率低下(内存太大)
2 - 转换为 TBase* 而不是转换为数组中的 void*,但会失去一般性。 (可能我接下来会尝试)
你看到其他解决方案了吗?
【问题讨论】:
-
会简单地转换到
TBase*之前转换到void*解决问题让您满意吗? (See here) -
要明确一点:你的一些派生类有虚方法。其他人没有。而且 TBase 本身很小,添加一个 vtable 指针会导致内存大小显着增加。对吗?
-
您考虑过使用模板吗?
-
@DaleWilson 大小无关紧要。如果
TBase中有 1000 个ints,这仍然行不通。 -
@gha.st :这在多重继承的情况下不起作用。请参阅帖子中的更新。