Skip to content

D Pointer subclass lazy factory technique

Heikki Johannes Hildén edited this page Jun 22, 2016 · 1 revision

To avoid initialization order fiascoes.

Base class:
// b.h
#ifndef B_H
#define B_H

#include <QWidget>
#include <QScopedPointer>

class BPrivate;

class B : public QWidget
{
    Q_OBJECT

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

protected:
    typedef BPrivate *(* BPrivateFactory)(B *);

    B(BPrivateFactory factory, QWidget *parent = 0);

    const QScopedPointer<BPrivate> d_ptr;

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

#endif // B_H
// b_p.h
#ifndef B_P_H
#define B_P_H

#include <QtGlobal>

class B;

class BPrivate
{
    Q_DISABLE_COPY(BPrivate)
    Q_DECLARE_PUBLIC(B)

public:
    BPrivate(B *q);
    virtual ~BPrivate();

    B *const q_ptr;
};

#endif // B_P_H
// b.cpp
#include "b.h"
#include "b_p.h"
#include <QDebug>

BPrivate::BPrivate(B *q)
    : q_ptr(q)
{
    qDebug() << "BPrivate::BPrivate";
}

BPrivate::~BPrivate()
{
    qDebug() << "BPrivate::~BPrivate";
}

B::B(QWidget *parent)
    : QWidget(parent),
      d_ptr(new BPrivate(this))
{
    qDebug() << "B::B";
}

B::~B()
{
    qDebug() << "B::~B";
}

B::B(BPrivateFactory factory, QWidget *parent)
    : QWidget(parent),
      d_ptr(factory(this))
{
    qDebug() << "B::B (protected)";
}
Subclass (1)
// c.h
#ifndef C_H
#define C_H

#include "b.h"

class CPrivate;

class C : public B
{
    Q_OBJECT

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

protected:
    C(BPrivateFactory factory, QWidget *parent = 0);

private:
    Q_DISABLE_COPY(C)
    Q_DECLARE_PRIVATE(C)

    static BPrivate *factory(B *q);
};

#endif // C_H
// c_p.h
#ifndef C_P_H
#define C_P_H

#include "b_p.h"

class C;

class CPrivate : public BPrivate
{
    Q_DISABLE_COPY(CPrivate)
    Q_DECLARE_PUBLIC(C)

public:
    CPrivate(C *q);
    ~CPrivate();
};

#endif // C_P_H
// c.cpp
#include "c.h"
#include "c_p.h"
#include <QDebug>

CPrivate::CPrivate(C *q)
    : BPrivate(q)
{
    qDebug() << "CPrivate::CPrivate";
}

CPrivate::~CPrivate()
{
    qDebug() << "CPrivate::~CPrivate";
}

C::C(QWidget *parent)
    : B(&C::factory, parent)
{
    qDebug() << "C::C";
}

C::~C()
{
    qDebug() << "C::~C";
}

C::C(BPrivateFactory factory, QWidget *parent)
    : B(factory, parent)
{
    qDebug() << "C::C (protected)";
}

BPrivate *C::factory(B *q)
{
    return new CPrivate(static_cast<C *>(q));
}
Subclass (2)
// d.h
#ifndef D_H
#define D_H

#include "c.h"

class DPrivate;

class D : public C
{
    Q_OBJECT

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

private:
    Q_DISABLE_COPY(D)
    Q_DECLARE_PRIVATE(D)

    static BPrivate *factory(B *q);
};

#endif // D_H
// d_p.h
#ifndef D_P_H
#define D_P_H

#include "c_p.h"

class D;

class DPrivate : public CPrivate
{
    Q_DISABLE_COPY(DPrivate)
    Q_DECLARE_PUBLIC(D)

public:
    DPrivate(D *q);
    ~DPrivate();
};

#endif // D_P_H
// d.cpp
#include "d.h"
#include "d_p.h"
#include <QDebug>

DPrivate::DPrivate(D *q)
    : CPrivate(q)
{
    qDebug() << "DPrivate::DPrivate";
}

DPrivate::~DPrivate()
{
    qDebug() << "DPrivate::~DPrivate";
}

D::D(QWidget *parent)
    : C(&D::factory, parent)
{
    qDebug() << "D::D";
}

D::~D()
{
    qDebug() << "D::~D";
}

BPrivate *D::factory(B *q)
{
    return new DPrivate(static_cast<D *>(q));
}

Output:

BPrivate::BPrivate
CPrivate::CPrivate
DPrivate::DPrivate
B::B (protected)
C::C (protected)
D::D
D::~D
C::~C
B::~B
DPrivate::~DPrivate
CPrivate::~CPrivate
BPrivate::~BPrivate