简体   繁体   English

C ++:将派生指针转换为void指针,然后转换为抽象指针,并访问成员函数

[英]C++: Casting derived pointer to void pointer and then to abstract pointer, and accessing member functions

I have a controller function to take care of a number of objects whose specific classes are all derived from a pure virtual class. 我有一个控制器函数来处理许多对象,这些对象的特定类都从纯虚拟类派生。

class Abstract {
public:
    virtual bool ReadyForWork() = 0;
    virtual void DoWork() = 0;
};

Then I have the following: 然后我有以下内容:

class Specific : public virtual Abstract {
public:
    bool ReadyForWork();
    void DoWork();
};

The program creates an instance of Specific and assigns it to a void pointer in a chain. 该程序将创建一个Specific实例,并将其分配给链中的void指针。

vChain->Append(new Specific());

So far, so good. 到现在为止还挺好。 When the controller function kicks in and tries to access Specific's implementation of Abstract's virtual functions, though... eww. 当控制器功能启动并尝试访问Abstract的虚拟功能的Specific的实现时,... eww。

The Specific object is there, I can access its contents by casting vChain's inner void* to Specific* and it all checks out, so bad memory isn't the issue. 特定对象在那里,我可以通过将vChain的内部void *强制转换为特定对象*来访问其内容,然后全部检查出来,因此内存不足不是问题。 But the moment I cast the void* to Abstract*, the compiler loses the references to Specific's implementations, changing the function addresses to something entirely different from what was previously there - even though the pointer to the object itself is correct. 但是,当我将void *强制转换为Abstract *时,编译器会丢失对Specific的实现的引用,从而将函数地址更改为与以前的地址完全不同的内容,即使指向对象本身的指针是正确的。 Trying

// ...
Abstract *vWorkObj = (Abstract*)vChain->GetObj();
    if (vWorkObj->ReadyForWork()) {
// ...

results in the following in my face: 导致以下结果:

Unhandled exception at 0x00000054 in Proj.exe:
0xC0000005: Access violation executing location 0x00000054.

But if I do this instead 但是如果我这样做

// ...
Abstract *vWorkObj = (Specific*)vChain->GetObj();
    if (vWorkObj->ReadyForWork()) {
// ...

it runs without a hiccup. 它没有打ic地运行。 Unfortunately, that doesn't help me much, as there are going to be multiple classes inheriting from Abstract. 不幸的是,这对我没有多大帮助,因为将会有多个继承自Abstract的类。

I've tried something similar in a proof-of-concept project and it ran smoothly: 我已经在概念验证项目中尝试了类似的操作,并且运行顺利:

// ...
bool ReadyForWork(Abstract *pObjPtr) {
// ...

// ...
Specific *vObj = new Specific();
if (ReadyForWork(vObj)) {
// ...

Apparently the compiler doesn't like having to resolve inheriting classes at runtime. 显然,编译器不喜欢必须在运行时解析继承的类。 Is there a way to access an inheritor of an abstract class without explicitly telling the compiler which inheritor it is? 是否有访问一个抽象类的继承者没有明确告诉它继承它是编译器的方法吗?

I suspect the casting to and from void* might be what's causing the compiler to lose its bearings, but it would save some hassle if the chain could be kept as generic as possible. 我怀疑强制转换为void *和从void *进行强制转换可能是导致编译器失去方向的原因,但是如果可以尽可能地保持通用链,则会节省一些麻烦。

I'm using VS2013 Express for Windows Desktop. 我正在使用Windows桌面的VS2013 Express。 Thanks for your time. 谢谢你的时间。

The direct source of the problem is probably that you are using virtual inheritance, which complicates the layout of your class. 问题的直接根源可能是您在使用虚拟继承,这会使类的布局复杂化。 It is usually only needed in complicated multiple inheritance scenarios, so maybe you wouldn't need it. 通常仅在复杂的多继承方案中才需要它,因此也许您不需要它。

You want a pointer to the Abstract subobject of a Specific , which might not be the same memory address in your case. 您需要一个指向SpecificAbstract子对象的指针,在您的情况下,该子对象可能不是相同的内存地址。 So if you store Abstract* in vChain , make sure you store the correct address by converting to a Abstract* first: 因此,如果将Abstract*存储在vChain ,请确保先转换为Abstract*来存储正确的地址:

vChain->Append(static_cast<Abstract*>(new Specific()));

Aside of that there is the question why vChain contains void* in the first place. 除此之外,还有一个问题,为什么vChain包含void* If it would store Abstract* no explicit casts would be necessary at all and the compiler would figure out the correct pointers automatically. 如果它将存储Abstract*根本不需要显式强制转换,并且编译器将自动找出正确的指针。

In general, when you convert a foo* to void* , it is only safe to convert back to the exact same type. 通常,将foo*转换为void*安全地转换回完全相同的类型是安全的。 There are cases where it works, there are cases where it happens to work, but in basically every case you are better off following this rule. 在某些情况下它会起作用,在某些情况下它会起作用,但是基本上在每种情况下,您都应该遵循此规则。

If you intend to convert your void* later into an abstract* , convert your foo* to an abstract* before converting it to a void* . 如果您打算稍后将void*转换为abstract* ,请先将foo*转换为abstract* 然后再将其转换为void* The best kind of such conversion is implicit. 这种转换的最佳方式是隐式的。

abstract* p = new foo;
void* v = static_cast<void*>(p);
abstract*p2 = static_cast<abstract*>(v);

finally, if you know you are going to convert to an abstract* later, consider changing the type of pointer you store meanwhile to an abstract* . 最后,如果您知道以后要转换为abstract* ,请考虑将同时存储的指针类型更改为abstract*

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM