[Qt-interest] QList<T> conversion

Thiago Macieira thiago at kde.org
Tue Feb 1 23:43:29 CET 2011


On Tuesday, 1 de February de 2011 17:36:24 Guillaume CLEMENT wrote:
> Usually the problem is, what happens if the "doFoo" function adds an
> incompatible object to the list ? It can do so, since the list is a
> QList<QObject*>.

Right, this is a problem. That's why this is allowed in C++:

	struct Base {};
	struct Derived: Base { void someDerivedMethod(); };

	Derived d;

	Derived *d_ptr 	Base *b_ptr 
but the following isn't:

	Derived **d_ptr_ptr 	Base **b_ptr_ptr 
Because if the above were allowed, you could do:

	Base b;
	Base *b_ptr 	b_ptr_ptr 	(*d_ptr_ptr)->someDerivedMethod();

> For example with this code :
> 
> 
> QList<A*> *firstList > QList<QObject*> *secondList > 
> secondList ->append(new B());                              // Wh
re B
> inherits QObject but not A
> 
> A *a > What happens ? My guess is that A will be invalid and reading / writing to
> it would be bad at this stage.
> 
> 
> 
> Some B was just added in firstList, although it is not a A. But firstList is
> a QList<A*>.

Right, your example would cause problems. It's introduced by the 
reinterpret_cast.

But that's not what I had suggested. I never suggested keeping a different 
QList pointer to the same list. I suggested making a copy but keeping the same 
data:

	QList<A *> firstList 	QList<QObject *> secondList 		*reinterpret_cast<QList<QObject *> *>(&firstList);

By the QList construction, the above works, even the implicit sharing. It 
means that, just after my lines above, firstList and secondList share the same 
data.

However, the moment that you do:

	secondList << new B;

Then they no longer share the same bits. The original list still has only A 

elements.

This concept is called Co-variance and Contra-variance (nothing to do with 
QVariant). Read more at:

http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

It also says:
> The operator which constructs array types from element types is usually
> covariant on the base type: since String ≤ Object then ArrayOf(String) ≤
> ArrayOf(Object). Note that this is only correct (i.e. type safe) if the
> array is immutable; if insert and remove operators are permitted, then
> the insert operator is covariant (e.g. one can insert a String into an
> ArrayOf(Object)) and the remove operator is contravariant (e.g. one can
> remove an Object from an ArrayOf(String)). Since the mutators have
> conflicting variance, mutable arrays should be invariant on the base
> type.

The C++ support for covariants and contravariants is incomplete. C++ supports 
covariant returns in virtual overrides, but not contravariant arguments, since 
arguments are used in overloading resolu
ion.

However, C++ doesn't technically need contravariant overriding. Given the two 
types above:

struct BaseClass
{
    virtual void doSomething(Derived *);
};

struct DerivedClass: public BaseClass
{
    virtual void doSomething(Base *);
private:
    virtual void doSomething(Derived *d)
#ifdef __GXX_EXPERIMENTAL_CXX0X__
	final
#endif
	;
};

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
  Senior Product Manager - Nokia, Qt Development Frameworks
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: This is a digitally signed message part.
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20110201/3391db9e/attachment.bin 


More information about the Qt-interest-old mailing list