在Qt Pimpl类中创建Private子类时出现多个定义错误

时间:2016-05-16 14:32:47

标签: c++ qt inheritance pimpl-idiom

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

这是一个基本的例子:

基类

标题

// 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)
{}

私人课程

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

子类

标题

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

有谁知道我在这里做错了什么?

2 个答案:

答案 0 :(得分:0)

此构造函数声明:

Gadget(GadgetPrivate &d, QWidget *parent)

需要引用GadgetPrivate,此时此引用只是一个前向声明的类。切换到指针的参数类型,你可以没事:

Gadget(GadgetPrivate *d, QWidget *parent)

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

一些注意事项:

  • 首先,为QScopedPointer使用d_ptr。这样可以防止因不删除d_ptr而造成的内存泄漏。 q_ptr应该仍然是原始指针。
  • 关于PIMPL习语的
  • This Q&A非常精彩,包括很多关于&#34; gotcha&#34; s等的提示。
  • Marc Mutz写了一篇关于Qt和pimpl成语的精彩文章。他们值得checking out。我链接到文章的第2部分,因为它涉及内部的更多细节。

答案 1 :(得分:0)

解决方案#1:

使内联的私有基类中的所有内容,即更改此内容,

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