c++ - 错误 : forward declaration of ‘class SActionPrivate’ when using PIMPL

标签 c++ qt cmake pimpl-idiom moc

在Qt程序中我实现了Pimpl方法,有3个文件

saction.cpp

saction.h

saction_p.h - with a private class sactionPrivate

该代码基于 kdelibs 中的代码。我正在使用 CMAKE 作为构建系统。所以编译的时候报错

build/moc_saction.cpp:73:22: 错误:无效使用不完整类型‘class SActionPrivate’ actions/saction.h:492:18: 错误:‘类 SActionPrivate’ 的前向声明

问题出在文件moc_saction.cpp,它不包含文件saction_p.h,只包含saction.h

所以我需要在生成的 moc 文件中手动添加行:

#include "../actions/saction_p.h"

我应该怎么做,才能不手动更正 moc 文件???

CMakeLists.txt

project(scalc)
cmake_minimum_required(VERSION 2.6)
find_package(Qt4 REQUIRED)

include_directories(
${QT_INCLUDES} 
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/actions
)

set(scalc_SRCS 

actions/saction.cpp

main.cpp )

set(CMAKE_AUTOMOC ON)

add_executable(scalc ${scalc_SRCS} )

target_link_libraries(scalc ${QT_QTCORE_LIBRARY}  ${QT_QTGUI_LIBRARY})
install(TARGETS scalc RUNTIME DESTINATION bin)

actions/saction.h

#ifndef SACTION_H
#define SACTION_H

#include <QtGui/QWidgetAction>

class SAction : public QWidgetAction
{
    Q_OBJECT
    public:
        explicit SAction(QObject *parent);
        virtual ~SAction();

    private:
        friend class SActionPrivate;
        class SActionPrivate* const d;
        Q_PRIVATE_SLOT(d, void slotTriggered())
};


#endif

actions/saction_p.h

#ifndef SACTION_P_H
#define SACTION_P_H

class SAction;


class SActionPrivate
{
    public:

        SActionPrivate():q(0)
        {
        }

        void slotTriggered();

        void init(SAction *q_ptr);

        SAction *q;

};

#endif

actions/saction.cpp

#include "saction.h"
#include "saction_p.h"

#include <QtGui/QApplication>
#include <QtGui/QHBoxLayout>
#include <QtGui/QShortcutEvent>
#include <QtGui/QToolBar>

void SActionPrivate::init(SAction *q_ptr)
{
  q = q_ptr;

  QObject::connect(q, SIGNAL(triggered(bool)), q,     SLOT(slotTriggered()));

    q->setProperty("isShortcutConfigurable", true);
}


void SActionPrivate::slotTriggered()
{}

SAction::SAction(QObject *parent)
    : QWidgetAction(parent), d(new SActionPrivate)
{
    d->init(this);
}

SAction::~SAction()
{
    delete d;
}

main.cpp

#include "saction.h"

int main(int argc, char** argv)
{
    SAction gg(new QWidget());
}

由cmake moc_saction.cpp生成

#include "../actions/saction.h"
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'kaction.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 63
#error "This file was generated using the moc from 4.8.6. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_SAction[] = {

// content:
  6,       // revision
  0,       // classname
  0,    0, // classinfo
  1,   14, // methods
  0,    0, // properties
  0,    0, // enums/sets
  0,    0, // constructors
  0,       // flags
  0,       // signalCount

// slots: signature, parameters, type, tag, flags
  9,    8,    8,    8, 0x08,

  0        // eod
};

static const char qt_meta_stringdata_SAction[] = {
"SAction\0\0slotTriggered()\0"
};

void SAction::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
    Q_ASSERT(staticMetaObject.cast(_o));
    SAction *_t = static_cast<SAction *>(_o);
    switch (_id) {
    case 0: _t->d->slotTriggered(); break;
    default: ;
    }
}
Q_UNUSED(_a);
}

const QMetaObjectExtraData SAction::staticMetaObjectExtraData = {
0,  qt_static_metacall 
};

const QMetaObject SAction::staticMetaObject = {
{ &QWidgetAction::staticMetaObject, qt_meta_stringdata_SAction,
  qt_meta_data_SAction, &staticMetaObjectExtraData }
};

#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &SAction::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION

const QMetaObject *SAction::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}

void *SAction::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_SAction))
    return static_cast<void*>(const_cast< SAction*>(this));
return QWidgetAction::qt_metacast(_clname);
}

int SAction::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidgetAction::qt_metacall(_c, _id, _a);
if (_id < 0)
    return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
    if (_id < 1)
    qt_static_metacall(this, _c, _id, _a);
    _id -= 1;
}
return _id;
}
QT_END_MOC_NAMESPACE

最佳答案

对了,这里有两个问题:

  • 缺少生成 moc 的 cmake 二进制目录的包含路径

    ${CMAKE_CURRENT_BINARY_DIR}
    
  • 您需要在相应源文件的末尾包含 moc 文件

    #include "moc_saction.cpp"
    

关于c++ - 错误 : forward declaration of ‘class SActionPrivate’ when using PIMPL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27626977/

相关文章:

qt - 如何在 QML 中将 RowLayout 正确拆分为两个相等的字段?

c++ - CMake 链接器无法正常工作

cmake - 如何将脚本的依赖项添加到 CMake 中的目标?

C++11 - 绑定(bind)排序函数

c++ - 使用 glCreateBuffers 时出现访问冲突错误

c++ - "error: C2275: ' QMouseEvent ' : illegal use of this type as an expression"

c++ - this 指针和 QSharedPointer

c++ - 进程 P2 可以通过什么方式访问另一个进程 P1 的局部变量?

c++ - 在 qt widgets 应用程序中显示 cmd 终端

c++ - CLion 无法识别 SDL2_image