PDA

View Full Version : Why Qt do not use interfaces for their classes?



atomic
17th October 2015, 17:45
Hi all,

In my company I started implementing a library where some of classes should inherit from Qt classes.

I look on source code for example of QAuthenticator class and I see that it does not use interface ( does not inherit any interface / pure abstract class ) but use PIMPL idiom ( it is fine ).

And now when I want for example change the QAuthenticator implementation without change public API of this class I can not do that.

I would like ask you if do you think that good library should be build using interfaces and PIMPL idiom? For example:



class IAuthenticator
{
public:
virtual ~IAuthenticator() {}
virtual QString user() const = 0;
virtual void setUser(const QString &user) = 0;

virtual QString password() const = 0;
virtual void setPassword(const QString &password) = 0;

// etc ...
};


class AuthenticatorPrivate
{
public:
QString method;
QString user;
QString password;
QString realm;
};


class Authenticator : public IAuthenticator
{
public:
// ...

private:
QScopedPointer<AuthenticatorPrivate> d; // d-pointer == PIMPL
};

anda_skoa
17th October 2015, 19:45
Interfaces are nice when you expect multiple implementations of something.
E.g. Qt uses those in such places, e.g. QAbstractButton, QAbstractItemModel, etc.

Sometimes the API class itself is constant but different implementations get loaded, e.g. QWindow and QPlatformWindow.

QAuthenticator is a value class, a structured data container, like QUrl, QColor, QString, etc.
They basically just bundle different primitive items into one compound item.

Value classes in C++ are almost never derived from anything, at least not virtually, since that can easily lead to unpleasent things like slicing.

Cheersm
_

atomic
18th October 2015, 11:22
Ok, so can you tell me how I should design classes in my library using Qt?

For example it is a good?



class AuthenticatorPrivate : public QSharedData
{
public:
AuthenticatorPrivate();
~AuthenticatorPrivate();

QString method;
QString user;
QString password;
};

class Authenticator
{
public:
Authenticator();

QString method() const;
void setMethod(const QString &method);

QString user() const;
void setUser(const QString &user);

QString password() const;
void setPassword(const QString &password);

private:
QSharedDataPointer<AuthenticatorPrivate> d;
};


so all 'private' classes inherit from QSharedData and then this private class is store in private section of my class as QSharedDataPointer<AuthenticatorPrivate> d;,
It is a good design?

Regards,

anda_skoa
18th October 2015, 12:09
If you want your objects to have the copy-on-write behavior that Qt's value classes have, then this is a good approach.

Cheers,
_

atomic
18th October 2015, 12:54
So all 'private' class should / can be inherited from QSharedData?

I saw that PIMPL idiom in different libraries is implemented on very different way, for example one library use struct for private class, when another use class, one library use pure pointer for private class, when another use smart pointer etc...

I look for 'general' design technics for all my classes which should use PIMPL idiom.

Regards,

anda_skoa
18th October 2015, 14:45
The type of pointer being used depends on the use case.

QSharedData and QSharedDataPointer are nice helper classes when you want to have reference countred, copy-on-write data classes.

A shared pointer can be used if multiple copies of a API object should point to the same private.

You can use a QScopedPointer if the private is always allocated by the API class constructor.

You can use a raw pointer or a shared pointer if the private is not always allocated as long as the API class is.

Cheers,
_