在 Qt Pimpl class 中创建 Private subclass 时出现多重定义错误

Multiple definition error when creating Private subclass in Qt Pimpl class

我一直在尝试按照 this Qt wiki page 上的说明实现 Pimpl class,其中私有 class 继承自另一个私有基础 class。

这是一个基本示例:

基地class

页眉

// gadget.h 
#ifndef GADGET_H
#define GADGET_H

#include <QWidget>

class GadgetPrivate;

class Gadget : public QWidget
{
    Q_OBJECT

public:
    explicit Gadget(QWidget *parent = 0);
    ~Gadget();

protected:
    Gadget(GadgetPrivate &d, QWidget *parent = 0);

    GadgetPrivate *d_ptr;

private:
    Q_DISABLE_COPY(Gadget)
    Q_DECLARE_PRIVATE(Gadget)
};

#endif // GADGET_H

实施

// gadget.cpp
#include "gadget.h"
#include "gadget_p.h"

Gadget::Gadget(QWidget *parent)
    : QWidget(parent),
      d_ptr(new GadgetPrivate(this))
{}

Gadget::~Gadget() {}

Gadget::Gadget(GadgetPrivate &d, QWidget *parent)
    : QWidget(parent),
      d_ptr(&d)
{}

私人class

// gadget_p.h
#ifndef GADGET_P_H
#define GADGET_P_H

#include "gadget.h"

class GadgetPrivate
{
    Q_DECLARE_PUBLIC(Gadget)

public:
    GadgetPrivate(Gadget *q);

    Gadget *q_ptr;
};

GadgetPrivate::GadgetPrivate(Gadget *q)
    : q_ptr(q)
{}

#endif // GADGET_P_H

亚class

页眉

// gizmo.h
#ifndef GIZMO_H
#define GIZMO_H

#include "gadget.h"

class GizmoPrivate;

class Gizmo : public Gadget
{
    Q_OBJECT

public:
    explicit Gizmo(QWidget *parent = 0);
    ~Gizmo();

private:
    Q_DISABLE_COPY(Gizmo)
    Q_DECLARE_PRIVATE(Gizmo)
};

#endif // GIZMO_H

实施

// gizmo.cpp
#include "gizmo.h"
#include "gadget_p.h"

class GizmoPrivate : public GadgetPrivate
{
    Q_DECLARE_PUBLIC(Gizmo)

public:
    GizmoPrivate(Gizmo *q);
};

GizmoPrivate::GizmoPrivate(Gizmo *q)
    : GadgetPrivate(q)
{}

Gizmo::Gizmo(QWidget *parent)
    : Gadget(*new GizmoPrivate(this), parent)
{}

Gizmo::~Gizmo() {}

我收到以下错误:

 In function `GadgetPrivate::GadgetPrivate(Gadget*)':
 error: multiple definition of `GadgetPrivate::GadgetPrivate(Gadget*)'

有谁知道我做错了什么吗?

这个构造函数声明:

Gadget(GadgetPrivate &d, QWidget *parent)

需要引用 GadgetPrivate,此时它只是前向声明的 class。把参数类型换成指针就可以了:

Gadget(GadgetPrivate *d, QWidget *parent)

和:

Gadget(GadgetPrivate *d, QWidget *parent)
  : QWidget(parent), d_ptr(d)
  {}

一些注意事项:

  • 首先,为您的 d_ptr 使用 QScopedPointer。这将防止您因未删除 d_ptr 而造成的内存泄漏。 q_ptr 应该保持原始指针。
  • This Q&A 关于 PIMPL 习语非常棒,包括很多关于 "gotcha" 等的提示。
  • Marc Mutz 撰写了一些关于 Qt 和 pimpl idiom 的精彩文章。他们身价 checking out。我链接到文章的第 2 部分,因为它详细介绍了内部结构。

解决方案 #1:

使私有库中的所有内容 class 内联,即更改此设置,

class GadgetPrivate
{
    Q_DECLARE_PUBLIC(Gadget)

public:
    GadgetPrivate(Gadget *q);

    Gadget *q_ptr;
};

GadgetPrivate::GadgetPrivate(Gadget *q)
    : q_ptr(q)
{
}

到,

class GadgetPrivate
{
    Q_DECLARE_PUBLIC(Gadget)

public:
    GadgetPrivate(Gadget *q)
        : q_ptr(q)
    {
    }

    Gadget *q_ptr;
};

编译代码。

解决方案 #2:

这似乎也有效:

gadget_p.h

class GadgetPrivate
{
    Q_DECLARE_PUBLIC(Gadget)

public:
    GadgetPrivate(Gadget *q);

    Gadget *q_ptr;
};

gadget.cpp

#include "gadget.h"
#include "gadget_p.h"

GadgetPrivate::GadgetPrivate(Gadget *q)
    : q_ptr(q)
{
}

Gadget::Gadget(QWidget *parent)
    : QWidget(parent),
      d_ptr(new GadgetPrivate(this))
{
}

Gadget::~Gadget()
{
}

Gadget::Gadget(GadgetPrivate *d, QWidget *parent)
    : QWidget(parent),
      d_ptr(d)
{
}

GadgetPrivate 的实施已移至 gadget.cpp