2011-04-14 7 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' 

는 여기 선언을 떠나, 또는 내가 헤더 파일을 생성하고 해당 파일에 선언을 이동해야합니다 수 있습니까?

편집 :

#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; 

}; 
:
씨 제리 관 때문에 나는 그래서 우리는 그 가능성을 검토 할 수 AbstractConnection의 선언 여기에 넣어 것입니다, 일부 가상 함수가 구현이되지 않을 수 있습니다 것을 제안합니다 (씨 관 감사합니다)

해결 방법 : @ JCooper, @ iammilind 및 @Jerry Coffin에게 감사드립니다. AbstractConnection에서 소멸자를 제거한 후에 (실제로 아무것도 수행하지 않기 때문에) ConnectionMockup에서 Q_OBJECT를 제거하면 작동합니다.

+0

감사합니다. 나는 지금 그것을 교정했다. – Sasa

+0

@Sasa : 첫 번째 문장을 명시 적으로 수정하지 않았습니다. 선언 및 구현은 여기에서 동의어입니다. ;) – Xeo

+0

@ 0A0D : 사실, 그렇지 않습니다. 클래스 선언은 다음과 같습니다 : class myclass;'class myclass {/ * ... * /};'는 클래스 정의입니다. 그런 다음 클래스 구성원을 클래스 자체의 정의와 별도로 정의 할 수 있습니다. –

답변

14

네, 클래스와 그 멤버 함수를 하나의 파일로 정의하는 것은 전적으로 합법적이며 허용됩니다. 사실, 컴파일러의 관점에서 본질적으로 항상 그렇습니다. 헤더에 클래스 정의가 있고, 멤버 함수를 구현하는 소스 파일에 헤더를 포함합니다.

오류는 컴파일러 오류가 아닌 링커 오류와 유사합니다. 누락 된 것이 정확히 무엇을 게시했는지 분명하지 않습니다. 한 가지 가능성은 기본 클래스에 파생 클래스에서 구현하지 못한 순수 가상이 있지만 실제로는 이 아니며이 맞는지 확인하십시오. 기본 클래스는 순수하지을 어떤 virtual 기능이있는 경우

+1

오류 **의 원인을 찾을 수 있지만 해결 방법이 아닌 것 같아요 ** (헤더 파일에서 선언문을 옮기는 것을 제외하고). 나는 [여기] (http://stackoverflow.com/q/177468/353563) 비슷한 오류를 발견했다. 내 클래스 ConnectionMockup에 Q_OBJECT 매크로가 있고 헤더 파일이 없기 때문에 qt의 moc가이 소스를 건너 뛰고 추가 기능/코드/기타를 생성하지 않기 때문입니다. : -? – Sasa

+2

@Sasa Mockup에서 특별히 신호/슬롯을 사용하지 않으므로 수행중인 작업에 Q_OBJECT 매크로를 사용하지 않아야합니다. 제거를 시도 했습니까? – JCooper

+0

@JCooper 감사합니다! 방금 ConnectionMockup에서 Q_OBJECT를 제거하고 AbstractConnection (@iammilind 덕분에)에서 삭제했습니다. 이제 작동합니다. 하지만, Q_OBJECT가 없을 때 test_send_message에서 신호를 내보내는 것이 지금 어떻게 작동하는지 이해하지 못합니다. – Sasa

3

, 그것은 그렇지 않으면 vtable 또는 typeinfo에 대한 링커 오류를 제공, 정의는 최종 바이너리를 컴파일하는 동안 포함되어야합니다. 아래의 예를 살펴 보겠습니다 :

// 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 파일은 개체 파일을 만들기 위해 별도로 컴파일 한 다음 함께 연결할 수 있습니다. destructor의 - 질문에서

은, 내가 느끼는 것을, 당신은 어떻게 든 여전히 하나 개의 비 순수 가상 함수를 포함 class AbstractConnection의 .CPP/오브젝트 파일을 첨부하지 않는 것입니다. 해당 정의를 ConnectionMockup과 함께 컴파일하면 링커 오류가 나타나서는 안됩니다. 클래스 정의 자체에서 소멸자 본문을 포함하는 파일을 컴파일하거나 소멸자 본문을 정의 할 수 있습니다.

+0

+1 소멸자를 언급합니다. 그것을 제거한 후에 (실제로 아무것도하지 않기 때문에) 나는 오류가 적다. 고맙습니다. – Sasa

12

Q_OBJECT 매크로는 일련의 Meta Object 구성원 기능을 선언합니다. MOC 빌드 도구는 .h 파일을 구문 분석하고 이러한 함수 선언을 정의합니다. .cpp 파일은 구문 분석하지 않습니다. 귀하의 경우에는 MOC 도구가 .cpp 파일을 구문 분석하지 않았기 때문에 vtable을 찾을 수 없습니다. 해결 방법은 클래스 정의를 헤더 파일 내부로 이동하고 .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; 
} 

공지 클래스 정의에서`사용법 #include"myfile.moc ".

qmake가 #include 지시문이있는 파일에서 MOC 도구를 호출하기 때문에 작동합니다. 따라서 MOC는 .cpp 파일을 구문 분석하고 Meta Object 함수 정의를 생성하여 링커 오류를 해결합니다.