Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

STL et classe abstraites

7 réponses
Avatar
Mathieu Peyréga
Bonjour,

le code suivant qui permet de manipuler des classes template avec pour
paramètre une classe abstraite (via une référence bien sur) est-il à
votre avis conforme au standard C++

Cordialement,

Mathieu

#include <iostream>
#include <vector>

template <class T>
class ISequence
{
public:

typedef typename std::vector<T>::size_type size_type;
typedef typename std::vector<T>::reference reference;
typedef typename std::vector<T>::const_reference const_reference;

inline virtual ~ISequence(void) {}

virtual size_type Size(void) const = 0;
virtual void Clear(void) = 0;
virtual void Push_Back(const_reference value) = 0;

virtual const_reference operator[](size_type i) const = 0;
virtual reference operator[](size_type i) = 0;

}; // class ISequence<T>

template <class T>
class Sequence : public ISequence<T>
{
public:

typedef typename ISequence<T>::size_type size_type;
typedef typename ISequence<T>::reference reference;
typedef typename ISequence<T>::const_reference const_reference;

inline Sequence(void) {}
inline ~Sequence(void) {}

inline virtual size_type Size(void) const { return m_data.size(); }
inline virtual void Clear(void) { m_data.clear(); }
inline virtual void Push_Back(const_reference value)
{ m_data.push_back(value); }

inline virtual const_reference operator[](size_type i) const
{ return m_data[i]; }
inline virtual reference operator[](size_type i)
{ return m_data[i]; }

protected:
std::vector<T> m_data;

}; // class Sequence<T>

typedef ISequence< ISequence<int> > IPathSequence;

class PathSequence : public IPathSequence
{
public:

inline PathSequence(void) {}
inline ~PathSequence(void) {}

inline size_type Size(void) const { return m_data.Size(); }
inline void Clear(void) { m_data.Clear(); }
inline void Push_Back(const_reference value)
{
size_type i = m_data.Size(),
jmax = value.Size(),
j;
m_data.Push_Back(Sequence<int>());
for(j=0;j<jmax;++j)
{
m_data.Push_Back(value[j]);
}
}

inline virtual const_reference operator[](size_type i) const
{ return m_data[i]; }
inline virtual reference operator[](size_type i)
{ return m_data[i]; }

protected:
Sequence< Sequence<int> > m_data;

}; // class PathSequence

int main(int argc, char* argv)
{
ISequence<int> *ps1 = new Sequence<int>;
ISequence<int> *ps2 = new Sequence<int>;
ISequence<int> *ps3 = new Sequence<int>;

ISequence<int> & is1 = *ps1;
ISequence<int> & is2 = *ps2;
ISequence<int> & is3 = *ps3;

is1.Push_Back(1);
is2.Push_Back(2); is2.Push_Back(3);
is3.Push_Back(4); is3.Push_Back(5); is3.Push_Back(6);

IPathSequence *pIPathSeq = new PathSequence;
IPathSequence &IPathSeq = *pIPathSeq;

IPathSeq.Push_Back(is1);
IPathSeq.Push_Back(is2);
IPathSeq.Push_Back(is3);

std::cout << "IPathSeq contains " << IPathSeq.Size() << " elements" <<
std::endl;

return 0;
}

7 réponses

Avatar
giova
Vu d'avion ca me semble parfaitement conforme et meme tres propre, mais
j'avoue que tout ca est un peu nouveau pour moi, dpnc mon avis est a
prendre au conditionnel, au pire si tu utilise visual qui d'apres mon
formateur est le compilateur le plus a la norme, tu peux mettre le
niveau d'avertissement au max, ca pourrait te donner des indications.

En tout cas ton code colle parfaitement avec tout ce que j'ai pu voir
lors de ma formation, (exepté que tu utilise vector qui fait parti de la
STL et non du C++ traditionnel).

Mathieu Peyréga wrote:

Bonjour,

le code suivant qui permet de manipuler des classes template avec pour
paramètre une classe abstraite (via une référence bien sur) est-il à
votre avis conforme au standard C++

Cordialement,

Mathieu

#include <iostream>
#include <vector>

template <class T>
class ISequence
{
public:

typedef typename std::vector<T>::size_type size_type;
typedef typename std::vector<T>::reference reference;
typedef typename std::vector<T>::const_reference const_reference;

inline virtual ~ISequence(void) {}

virtual size_type Size(void) const = 0;
virtual void Clear(void) = 0;
virtual void Push_Back(const_reference value) = 0;

virtual const_reference operator[](size_type i) const = 0;
virtual reference operator[](size_type i) = 0;

}; // class ISequence<T>

template <class T>
class Sequence : public ISequence<T>
{
public:

typedef typename ISequence<T>::size_type size_type;
typedef typename ISequence<T>::reference reference;
typedef typename ISequence<T>::const_reference const_reference;

inline Sequence(void) {}
inline ~Sequence(void) {}

inline virtual size_type Size(void) const { return m_data.size(); }
inline virtual void Clear(void) { m_data.clear(); }
inline virtual void Push_Back(const_reference value)
{ m_data.push_back(value); }

inline virtual const_reference operator[](size_type i) const
{ return m_data[i]; }
inline virtual reference operator[](size_type i)
{ return m_data[i]; }

protected:
std::vector<T> m_data;

}; // class Sequence<T>

typedef ISequence< ISequence<int> > IPathSequence;

class PathSequence : public IPathSequence
{
public:

inline PathSequence(void) {}
inline ~PathSequence(void) {}

inline size_type Size(void) const { return m_data.Size(); }
inline void Clear(void) { m_data.Clear(); }
inline void Push_Back(const_reference value)
{
size_type i = m_data.Size(),
jmax = value.Size(),
j;
m_data.Push_Back(Sequence<int>());
for(j=0;j<jmax;++j)
{
m_data.Push_Back(value[j]);
}
}

inline virtual const_reference operator[](size_type i) const
{ return m_data[i]; }
inline virtual reference operator[](size_type i)
{ return m_data[i]; }

protected:
Sequence< Sequence<int> > m_data;

}; // class PathSequence

int main(int argc, char* argv)
{
ISequence<int> *ps1 = new Sequence<int>;
ISequence<int> *ps2 = new Sequence<int>;
ISequence<int> *ps3 = new Sequence<int>;

ISequence<int> & is1 = *ps1;
ISequence<int> & is2 = *ps2;
ISequence<int> & is3 = *ps3;

is1.Push_Back(1);
is2.Push_Back(2); is2.Push_Back(3);
is3.Push_Back(4); is3.Push_Back(5); is3.Push_Back(6);

IPathSequence *pIPathSeq = new PathSequence;
IPathSequence &IPathSeq = *pIPathSeq;

IPathSeq.Push_Back(is1);
IPathSeq.Push_Back(is2);
IPathSeq.Push_Back(is3);

std::cout << "IPathSeq contains " << IPathSeq.Size() << " elements" <<
std::endl;

return 0;
}



Avatar
Christophe de VIENNE
giova wrote:
[snip]
au pire si tu utilise visual qui d'apres mon
formateur est le compilateur le plus a la norme, tu peux mettre le
niveau d'avertissement au max, ca pourrait te donner des indications.


Heu, de quelle version parlait-il ? Vous a-t-il parlé de Commeau ?


En tout cas ton code colle parfaitement avec tout ce que j'ai pu voir
lors de ma formation, (exepté que tu utilise vector qui fait parti de la
STL et non du C++ traditionnel).


<vector> fait partie de la norme standard.


A+

Christophe

Avatar
Mathieu Peyréga
Vu d'avion ca me semble parfaitement conforme et meme tres propre, mais
j'avoue que tout ca est un peu nouveau pour moi, dpnc mon avis est a
prendre au conditionnel, au pire si tu utilise visual qui d'apres mon
formateur est le compilateur le plus a la norme, tu peux mettre le
niveau d'avertissement au max, ca pourrait te donner des indications.

En tout cas ton code colle parfaitement avec tout ce que j'ai pu voir
lors de ma formation, (exepté que tu utilise vector qui fait parti de la
STL et non du C++ traditionnel).


Que visual soit le comilateur le plus à la norme m'étonne un peu...
A mon avis, gcc et en particulier sa toute dernière version 3.4.0 la
respecte beaucoup mieux...

Cela dit, mon propos était plus clairement :

à t'on le droit d'utiliser un object du type std::vector<IObject> où
IObject est une classe abstraite... Si je suis bien, c'est ce qui se
passe dans mon exemple quand je manipule un ISequence< ISequence<int> >
puisque en interne, l'implémentation manipule un
std::vector<ISequence<int> >
Hors, si j'ai bien compris ce que j'ai lu dans la norme, on ne peut
utiliser dans un conteneur STL que des objects qui respectent un certain
nombre de contrainte dont être "CopyConstructible" ce qui n'est
manifestement pas le cas lorsqu'on a une classe abstraite (à moins que
j'ai mal compris le tableau récapitulant les contraintes)

De plus, dans la norme, la signature de la méthode resize de
std::vector<T> est :

void resize(size_type new_size, value_type x = T());

et non pas ce qui est implémenté dans visual ou g++ :

void resize(size_type new_size, const value_type& x = T());

En passant sur le fait que l'implémentation gcc et visual me parait plus
"intelligente" que la norme dans le sens où elle évite un l'appel du
constructeur de recopie.

En gros, j'ai l'impression que mon code (qui compile et linke) ne
respecte pas la norme à cause de ce point mais j'aurais aimé avoir
d'autres avis.

Cordialement,

Mathieu

Avatar
Loïc Joly
Mathieu Peyréga wrote:

Vu d'avion ca me semble parfaitement conforme et meme tres propre,
mais j'avoue que tout ca est un peu nouveau pour moi, dpnc mon avis
est a prendre au conditionnel, au pire si tu utilise visual qui
d'apres mon formateur est le compilateur le plus a la norme, tu peux
mettre le niveau d'avertissement au max, ca pourrait te donner des
indications.

En tout cas ton code colle parfaitement avec tout ce que j'ai pu voir
lors de ma formation, (exepté que tu utilise vector qui fait parti de
la STL et non du C++ traditionnel).



La STL fait partie du C++ à 100%. Maintenant, comme je ne sais pas la
signification du mot traditionnel (j'imagine qu'il doit vouloir dire
quelquechose de différent pour Gaby et pour James... ;) )



Que visual soit le comilateur le plus à la norme m'étonne un peu...
A mon avis, gcc et en particulier sa toute dernière version 3.4.0 la
respecte beaucoup mieux...


Quelqu'un a vu des benchs récents ? Les derniers que j'ai vu
concernaient VC 6.0 et gcc 2.95.


Cela dit, mon propos était plus clairement :

à t'on le droit d'utiliser un object du type std::vector<IObject> où
IObject est une classe abstraite...


Non.

--
Loïc


Avatar
Mathieu Peyréga
à t'on le droit d'utiliser un object du type std::vector<IObject> où
IObject est une classe abstraite... Si je suis bien, c'est ce qui se
passe dans mon exemple quand je manipule un ISequence< ISequence<int> >
puisque en interne, l'implémentation manipule un
std::vector<ISequence<int> >


Autant pour moi avec la surcharge, c'est bien le Sequence<Sequence<int>
qui est manipulé...
Et l'objet "interdit" que je manipule n'est utilisé qu'au travers d'une

référence et du polymorphisme...
En fait, ce code compile si on utilise les STL livrées avec gcc ou
visual, mais pas avec la STLPort 4.6.2 pour laquel la signature de la
méthode resize est celle de la norme.
En effet, à ce moment là, le compilateur qui instancie le template
IPathSequence génère une erreur à cause de l'appel du constructeur par
défaut qui est bien évidement impossible pourune classe abstraite...

Hors, si j'ai bien compris ce que j'ai lu dans la norme, on ne peut
utiliser dans un conteneur STL que des objects qui respectent un certain
nombre de contrainte dont être "CopyConstructible" ce qui n'est
manifestement pas le cas lorsqu'on a une classe abstraite (à moins que
j'ai mal compris le tableau récapitulant les contraintes)

De plus, dans la norme, la signature de la méthode resize de
std::vector<T> est :

void resize(size_type new_size, value_type x = T());

et non pas ce qui est implémenté dans visual ou g++ :

void resize(size_type new_size, const value_type& x = T());

En passant sur le fait que l'implémentation gcc et visual me parait plus
"intelligente" que la norme dans le sens où elle évite un l'appel du
constructeur de recopie.

En gros, j'ai l'impression que mon code (qui compile et linke) ne
respecte pas la norme à cause de ce point mais j'aurais aimé avoir
d'autres avis.

Cordialement,

Mathieu



Avatar
Mathieu Peyréga
à t'on le droit d'utiliser un object du type std::vector<IObject> où
IObject est une classe abstraite...



Non.


Au moins c'est clair (et logique vu l'implémentation)... En question
subsidiaire :
est-ce qu'on a le droit de manipuler un pointeur ou une référence sur un
std::vector<IObject> ?


Avatar
kanze
Mathieu Peyréga wrote in message
news:...

à t'on le droit d'utiliser un object du type std::vector<IObject> où
IObject est une classe abstraite...


Non.


Au moins c'est clair (et logique vu l'implémentation)...


Il ne s'agissent pas d'une histoire d'implémentation. Un
std::vector<IObject> doit contenir des éléments (objets) de type
IObject. Si IObject est abstrait, il ne peut pas y avoir d'objets de ce
type.

En question subsidiaire :
est-ce qu'on a le droit de manipuler un pointeur ou une référence sur
un std::vector<IObject> ?


Si IObject est abstrait, il ne peut pas y avoir de type
std::vector<IObject>. Donc, pas de pointeurs et pas de références vers
un type qui ne peut même pas exister.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34