将类声明放在.cpp文件中

时间:2011-04-14 01:16:53

标签: c++ unit-testing qt

是否可以在同一个.cpp文件中进行类声明和实现?

我想借助mock对象进行一些单元测试。以下是我测试的一些示例:

// 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'

是否可以在此处留下声明,或者我必须创建头文件并将声明移到该文件中?

编辑:由于Jerry Coffin先生(谢谢Coffin先生)建议我可能没有实现一些虚拟功能,我将在此处声明AbstractConnection,以便我们可以审查这种可能性:< / p>

#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,@ immilind和@Jerry Coffin,我们有了解决方案。从AbstractConnection中删除析构函数后(因为它实际上什么都不做)并从ConnectionMockup中删除Q_OBJECT它就可以了。

3 个答案:

答案 0 :(得分:17)

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

#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文件并生成元对象函数定义,解决链接器错误。

答案 1 :(得分:14)

是的,在一个文件中定义一个类及其成员函数是完全合法的,也是允许的。实际上,从编译器的角度来看,实际上总是如此 - 在头文件中有类定义,并在源文件中包含实现其成员函数的头文件。

您遇到的错误看起来像链接器错误,而不是编译器错误。究竟缺少什么并不完全清楚你发布的内容。一种可能性是你的基类有一些你未能在派生类中实现的纯虚拟,但我根本不是 确定这是正确的。

答案 2 :(得分:3)

当Base类具有非纯的任何virtual函数时,在编译最终二进制文件时需要包含它的定义,否则它会为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; } 。请看下面的例子:

class AbstractConnection

现在Derived.cpp和Base.cpp的compile-link工作正常。两个.cpp文件也可以单独编译以创建目标文件,然后链接在一起。

从你的问题来看,我的感觉是,你并没有以某种方式附加destructor的.cpp / object文件,它仍包含一个非纯虚函数 - ConnectionMockup。如果您与{{1}}一起编译该定义,则不应出现链接器错误。您可以编译包含析构函数体的文件,也可以在类定义本身中定义析构函数体。