2011-04-14 97 views
17

是否有可能在同一个.cpp文件中有类声明和实现?将类声明放在.cpp文件中

我想在模拟对象的帮助下做一些单元测试。下面是我测试的一些例子:

// Some includes removed 

#include "abstractconnection.h" 

class ConnectionMockup : public AbstractConnection 
{ 
    Q_OBJECT 
public: 
    explicit ConnectionMockup(QObject *parent = 0); 

    bool isReady() const; 
    void sendMessage(const QString &message); 

    void test_send_message(const QString &message); 

    bool ready; 
    QStringList messages; 
}; 

ConnectionMockup::ConnectionMockup(QObject *parent) 
    : AbstractConnection(parent) 
{ 
    ready = true; 
} 

bool ConnectionMockup::isReady() const 
{ 
    return ready; 
} 

void ConnectionMockup::sendMessage(const QString &message) 
{ 
    messages.append(message); 
} 

void ConnectionMockup::test_send_message(const QString &message) 
{ 
    emit messageRecieved(message); 
} 

TestEmcProgram::TestEmcProgram(QObject *parent) : 
    QObject(parent) 
{ 
} 

void TestEmcProgram::open() 
{ 
    ConnectionMockup mockup; 
    EmcProgram program(&mockup); 
    QCOMPARE(... 
... 
... 

正如你所看到的,类ConnectionMockup仅由类TestConnection使用,我不需要任何其他地方。所以,当我尝试编译这个程序,我得到以下错误:

> testemcprogram.o: In function 
> `ConnectionMockup': 
> /home/sasa/Desktop/QtPro/FocoKernel-build-desktop/../FocoKernel/testemcprogram.cpp:29: 
> undefined reference to `vtable for 
> ConnectionMockup' 
> /home/sasa/Desktop/QtPro/FocoKernel-build-desktop/../FocoKernel/testemcprogram.cpp:29: 
> undefined reference to `vtable for 
> ConnectionMockup' testemcprogram.o: In 
> function `~ConnectionMockup': 
> /home/sasa/Desktop/QtPro/FocoKernel-build-desktop/../FocoKernel/testemcprogram.cpp:14: 
> undefined reference to `vtable for 
> ConnectionMockup' 

是否有可能离开这里声明,否则我必须创建头文件以及移动声明,该文件?

编辑:由于杰里先生棺材(谢谢你,先生的棺材)认为,我可能不会有一些虚函数来实现,我会把这里AbstractConnection的声明,使我们可以审查这种可能性:

#include <QObject> 

class AbstractConnection : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit AbstractConnection(QObject *parent = 0); 
    virtual ~AbstractConnection(); 

    virtual bool isReady() const = 0; 

signals: 
    void messageRecieved(const QString &message); 

public slots: 
    virtual void sendMessage(const QString &message) = 0; 

}; 

解决方案:感谢@JCooper,@iammilind和@Jerry Coffin,我们提供解决方案。从AbstractConnection中移除析构函数(因为它实际上什么都不做)并从ConnectionMockup中移除Q_OBJECT它就起作用。

+0

谢谢。我现在用文字纠正了它。 – Sasa 2011-04-14 01:42:07

+0

@Sasa:我明确没有纠正第一句话。声明和实现在这里是同义词。 ;) – Xeo 2011-04-14 01:53:21

+0

@ 0A0D:其实不,不是。类声明如下所示:'class myclass;'类似于:'class myclass {/ * ... * /};'是一个类定义。然后,可以从类自身的定义中分别定义类成员。 – 2011-04-14 01:55:20

回答

14

是的,它是完全合法的,并允许在一个文件中定义一个类及其成员函数。事实上,从编译器的角度来看,基本上总是这样 - 你在头文件中定义了类定义,并将该头文件包含在实现其成员函数的源文件中。

您遇到的错误看起来像链接器错误,而不是编译器错误。确切地说,缺少的东西并不完全清楚你发布的内容。一种可能性是你的基类有一些你在派生类中未能实现的纯虚函数,但我并不是,而是肯定是正确的。

+1

我想我可能会找到错误**的原因,但没有解决方案**(除了在头文件中移动声明)。我发现[这里](http://stackoverflow.com/q/177468/353563)类似的错误。我想这是因为我的类ConnectionMockup中有一个宏Q_OBJECT,并且因为我没有头文件,所以qt的moc跳过了这个源代码,并且不会生成加法函数/代码/不管。 : - ? – Sasa 2011-04-14 02:26:39

+2

@Sasa由于您在Mockup中没有专门使用任何信号/插槽,因此您不应_need_将Q_OBJECT宏用于您正在执行的操作。你尝试删除它吗? – JCooper 2011-04-14 03:14:45

+0

@JCooper谢谢!我刚刚从ConnectionMockup中移除了Q_OBJECT,并从AbstractConnection中删除了(感谢@iammilind),它现在可以工作。但是,它并不了解test_send_message中的发射信号如何在没有Q_OBJECT时出现。 – Sasa 2011-04-14 03:24:38

3

当基类有任何virtual函数,它是不是纯,它的定义需要在编译最终的二进制被包括在内,否则就给出了链接错误vtabletypeinfo。看下面的例子:

// Base.h 
struct Base { 
    virtual void fun() = 0; 
    virtual ~Base(); 
}; 

// Base.cpp 
#include"Base.h" 
Base::~Base() {} 

// Derived.cpp 
#include"Base.h" 
struct Derived : Base { 
    void fun() {} 
}; 

int main() { 
    Derived d; 
} 

现在编译链接为Derived.cpp和Base.cpp将工作正常。这两个.cpp文件也可以分别编译创建目标文件,然后链接在一起。

从你的问题,我的感觉是,你是不是莫名其妙地安装的class AbstractConnection在.cpp /目标文件,其中还含有一种非纯虚函数 - 它destructor。如果您还编译该定义以及ConnectionMockup,则不应出现链接器错误。您可以编译包含析构函数体的文件,也可以在类定义本身中定义析构函数体。

+0

+1提析析构函数。删除后(因为它实际上什么都没做),我得到了更少的错误。谢谢。 – Sasa 2011-04-14 03:26:31

12

Q_OBJECT宏声明了一组元对象成员函数。 MOC构建工具负责解析.h文件并定义这些函数声明。请注意,它不解析.cpp文件。在你的情况下,找不到vtable,因为MOC工具没有解析你的.cpp文件。解决方案是将您的类定义移动到头文件中,并将头添加到.pro文件中。第二种解决方案 - 有点“哈克” - 是做到以下几点:

#include <QObject> 
#include <QtDebug> 

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { value = 0; } 
    int getValue() const { qDebug() << "getValue()"; return value; } 

public slots: 
    void setValue(int value); 

signals: 
    void valueChanged(int newValue); 

private: 
    int value; 
}; 

#include "main.moc" 

void Counter::setValue(int value) 
{ 
    qDebug() << "setValue()"; 
    if (this->value != value) { 
    this->value = value; 
    emit valueChanged(value); 
    } 
} 

int main() 
{ 
    Counter a, b; 

    QObject::connect(
    &a, &Counter::valueChanged, 
    &b, &Counter::setValue); 

    a.setValue(12); 
    b.setValue(48); 

    return 0; 
} 

通知了`#包括“myfile.moc”之类的定义下。

这是可行的,因为qmake将使用#include指令调用任何文件上的MOC工具。因此,MOC将解析.cpp文件并生成元对象函数定义,从而解决链接器错误。

相关问题