PDA

View Full Version : QExplicitlySharedDataPointer



rhf417
26th May 2010, 22:26
I am using QExplicitlySharedDataPointer to create some explicitly shared data classes. I have four classes created as shown below:
CRootData inherits from QSharedData
CTestpointData inherits from CRootData
CRoot has an explicitly shared data pointer to CRootData
CTestPoint inherits from CRoot and has an explicitly shared data pointer to CTestpointData

When I create an instance of CTestPoint, I found that it has two sets of data members of m_id and m_name. This is not what I want. I only want one set of data referred by its d-pointer. How could I achieve this effect? Thanks.

-----------------------------------------------------------------------------------------------------------------

#include <QSharedData>
#include <QString>

class CRootData : public QSharedData
{
public:
CRootData() : m_id(0) {m_name.clear();}
CRootData(const CRootData &other)
: QSharedData(other), m_id(other.m_id), m_name(other.m_name) {}
virtual ~CRootData() {}

int m_id;
QString m_name;
};

class CTestpointData : public CRootData
{
public:
CTestpointData() : CRootData() {m_x=0; m_y=0;}
CTestpointData(const CTestpointData &other)
: CRootData(other), m_x(other.m_x), m_y(other.m_y) {}
~CTestpointData() {}

double m_x;
double m_y;
};

class CRoot
{
public:
CRoot() {d = new CRootData();}
CRoot(CRoot& other) : d(other.d) {}
CRoot(int id, QString name) {d = new CRootData(); setID(id); setName(name);}

virtual ~CRoot() {}

void setID(int id) {d->m_id = id;}
void setName(QString name) {d->m_name = name;}
int getID() const {return d->m_id;}
QString getName() const {return d->m_name;}

private:
QExplicitlySharedDataPointer<CRootData> d;
};

class CTestPoint : public CRoot
{
public:
CTestPoint() {d = new CTestpointData();}
CTestPoint(CTestPoint& other) : d(other.d) {}
~CTestPoint() {}

void setX(double x) {d->m_x = x;}
void setY(double y) {d->m_y = y;}
double getX() const {return d->m_x;}
double getY() const {return d->m_y;}

private:
QExplicitlySharedDataPointer<CTestpointData> d;
};

wysota
26th May 2010, 23:25
Don't add another "d" member in the subclass of the public component. The original "d" should either be in protected section or the base class of the public component should expose a protected constructor accepting a CRootData pointer and setting it on "d".

rhf417
27th May 2010, 21:03
I removed "d" member in CTestPoint and made "d" member in CRoot protected. Now, there is only one set of m_id and m_name members. However, I have to change the set/get functions of CTestPoint a little bit. For example, "void setX(double x) {d->m_x = x;}" has be changed to "void setX(double x) {((QExplicitlySharedDataPointer<CTestpointData>)d)->m_x = x;}". Although this is not so convenient, it is ok.


Given the existing classes above, now I need to generate a new "CBoard" subclass of CRoot and its corresponding private data class "CBoardData". This CBoard will contain an array of CTestPoint.


class CBoard : public CRoot
{
public:
CBoard();
CBoard(const CBoard& other);
~CBoard();

void addTestPoint(CTestPoint tp);
void removeTestPoint(CTestPoint tp);
CTestPoint getTestPoint(int index);
};

class CBoardData : public CRootData
{
public:
CBoardData();
CBoardData(const CBoardData &other);
~CBoardData();

QList<CTestPoint> m_testPoints;
};


There is a problem in the declaration of private data class "CBoardData": it uses CTestPoint, which is a public component class. This introduces a dual-direction reference between public component classes and private data classes, which is not a good design. How to avoid this dual reference while keeping all the public component classes explicitly shared?

wysota
27th May 2010, 21:51
You should be able to forward declare the private components in the public header and include the public header in the private one. As far as I remember the docs mention some conditions that need to be filled to be able to do that.