2

我有某种对象工厂(基于模板),这对我的目的非常有用。但是现在我尝试使用派生自 QObject 和纯抽象类(接口)的类,并且我遇到了奇怪的运行时错误。

这里是这个类的简单图(Derived)

class Interface  {
public:
    Interface(){}
    virtual ~Interface(){}    
    virtual int getResult() = 0;
};

class Derived : public QObject, public Interface {
    Q_OBJECT
public:
    explicit Derived(QObject *parent = 0);        
    int getResult();        
}; 

及其在derived.cpp中的实现:

#include "derived.h"    
Derived::Derived(QObject *parent)
    : QObject(parent) {
}    
int Derived::getResult() {
    return 55;
}

当我尝试将 void 指针强制转换为接口时,我会得到意想不到的(对我而言)行为,它可能是运行时错误,或其他方法调用(它取决于类的大小)。

#include "derived.h"    
void * create() {
    return new Derived();
}

int main(int argc, char *argv[]) {
    Interface * interface = reinterpret_cast<Interface *>(create());    
    int res = interface->getResult(); // Run-time error, or other method is called here
    return 0;
}

你能解释一下为什么我不能将 void 指针转换为接口吗?有什么解决方法吗?

感谢您的回复

4

3 回答 3

3

将指向派生类的指针重新解释为指向基类的指针会产生未定义的行为。多重继承突出了这一点:由于存在多个基类,并且两个基子对象必须具有不同的地址,因此它们不能具有与派生对象相同的地址。因此,您的create函数返回的指针指向 a Derived,但不一定指向Interface子对象。它可以指向QObject子对象,也可以都不指向。

最好的选择是返回Derived*Interface*从你的函数中返回;如果必须void*出于某种原因,那么您可以进行的唯一明确定义的转换是 back to Derived*,然后可以将其转换为Interface*使用标准转换。

通过使用void*你已经抛弃了类型的所有静态和动态知识;恢复该信息的唯一方法是转换回正确的类型。

于 2013-01-22T13:47:03.503 回答
1

与多重继承混合reinterpret_cast可能会导致各种问题。在您的情况下, thevoid*可能会指向 的QObject部分,而Derived不是Interface部分。

它可能会更好地使用 a dynamic_cast,它可以调整指针以指向派生类的正确子对象。

于 2013-01-22T13:46:20.747 回答
0

请注意,一般来说,需要这些类型的演员表是糟糕设计的标志。在您的特定情况下,您的工厂函数需要返回一个Interface*. void*在不涉及 C 接口的 C++ 中,这是不必要且不好的。

除此之外,工厂函数有点像 Java 的东西,只有在应用严格的设计方法时才需要,这通常会增加更多的绒毛,而不是为干净和无错误的代码做出贡献。

如果那不削减它,你会想要dynamic_cast。在 Qt for QObjects 中,您可以查看qobject_cast您的情况是否有任何优点。

于 2013-01-22T13:46:26.563 回答