Search code examples
c++qtinheritancepimpl-idiom

Multiple definition error when creating Private subclass in Qt Pimpl class


I have been trying to implement a Pimpl class, following the instructions on this Qt wiki page, in which the private class inherits from another private base class.

Here is a basic example:

Base class

Header

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

Implementation

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

Private 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

Subclass

Header

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

Implementation

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

I get the following error:

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

Does anyone know what I am doing wrong here?


Solution

  • Solution #1:

    Make everything in the private base class inline, i.e., changing this,

    class GadgetPrivate
    {
        Q_DECLARE_PUBLIC(Gadget)
    
    public:
        GadgetPrivate(Gadget *q);
    
        Gadget *q_ptr;
    };
    
    GadgetPrivate::GadgetPrivate(Gadget *q)
        : q_ptr(q)
    {
    }
    

    to,

    class GadgetPrivate
    {
        Q_DECLARE_PUBLIC(Gadget)
    
    public:
        GadgetPrivate(Gadget *q)
            : q_ptr(q)
        {
        }
    
        Gadget *q_ptr;
    };
    

    made the code compile.

    Solution #2:

    This also seems to work:

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

    Implementation of GadgetPrivate has moved to gadget.cpp.