2011-04-14 94 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文件並生成元對象函數定義,從而解決鏈接器錯誤。

相關問題