#include <vector>
#include <exception>
#include <iostream>
#include <iomanip>

using namespace std ;

// Question 1

typedef vector <unsigned int> CVEffectifs;

// Question 2 : voir suite question 2

class CHistogramme
{
    unsigned     m_Etendue;
    unsigned     m_EffTotal;
    CVEffectifs  m_Effectif;

public :
    CHistogramme (const unsigned Etendue = 1) throw (exception);
    CHistogramme (const CHistogramme & Histogramme) throw ();

    void Afficher (void) throw ();

    // Question 3 : voir suite question 3

    void Ajouter (const unsigned int Nbre) throw ();

    // Question 4 : voir suite question 4

    void Supprimer (const unsigned int Nbre) throw (exception);

    // Question 5 : voir suite question 5

    friend ostream & operator << (ostream & os,
                                  const CHistogramme & Histogramme) throw ();
    // Question 6 : voir suite question 6

    CHistogramme & operator = (const CHistogramme & Histogramme) throw ();

    // Question 7 : voir suite question 7

    CHistogramme & operator + (const unsigned int Nbre) throw ();

    // Question 8 : voir suite question 8

    CHistogramme & operator + (const CHistogramme & Histogramme) throw (exception);

}; // CHistogramme

// Suite question 2

inline CHistogramme::CHistogramme (const unsigned Etendue /* = 1 */) throw (exception)
    : m_Etendue (Etendue), m_EffTotal (0)
{
    if (0 == Etendue) throw exception ();
}

inline CHistogramme::CHistogramme (const CHistogramme & Histogramme) throw ()
    : m_Etendue  (Histogramme.m_Etendue),
      m_EffTotal (Histogramme.m_EffTotal),
      m_Effectif (Histogramme.m_Effectif)   {}

inline void CHistogramme::Afficher (void) throw ()
{
    for (int i = 0; i < m_Effectif.size (); ++i)
        cout << "classe " << setw (4) << i
             << " : " << setw (5) << m_Effectif [i] << endl;

} // Afficher()

// Suite question 3

inline void CHistogramme::Ajouter (const unsigned int Nbre) throw ()
{
    unsigned Classe = Nbre / m_Etendue;

    // Augmentation éventuelle de la taille du vecteur

    if (Classe >= m_Effectif.size ()) m_Effectif.resize (Classe + 1);

    // Tous les compteurs ajoutés sont automatiquement initialisés avec
    //   le constructeur par défaut du type unsigned, c-à-d. 0

    ++m_Effectif [Classe];
    ++m_EffTotal;

} // Ajouter()

// Suite question 4

inline void CHistogramme::Supprimer (const unsigned int Nbre) throw (exception)
{
    unsigned Classe = Nbre / m_Etendue;

    if (Classe >= m_Effectif.size ()) throw exception ();
    if (0 == m_Effectif [Classe])     throw exception ();

    --m_Effectif [Classe];
    m_EffTotal;

    // Diminution éventuelle de la taille du vecteur

    unsigned NbClasses = m_Effectif.size ();
    for (int i = NbClasses; i;)
    {
        if (m_Effectif [--i]) break;
        --NbClasses;
    }
    if (NbClasses < m_Effectif.size ()) m_Effectif.resize (NbClasses);

} // Supprimer()

// Suite question 5

inline ostream & operator << (ostream & os,
                              const CHistogramme & Histogramme) throw ()
{
    for (int i = 0; i < Histogramme.m_Effectif.size (); ++i)
        os << "classe " << setw (4) << i << " : " << setw (5)
           << Histogramme.m_Effectif [i] << endl;
    return os;

} // operator <<()

// Suite question 6

inline CHistogramme & CHistogramme::operator = (const CHistogramme & Histogramme) throw ()
{
    if (this == & Histogramme) return *this;

    m_Etendue  = Histogramme.m_Etendue;
    m_EffTotal = Histogramme.m_EffTotal;
    m_Effectif = Histogramme.m_Effectif;

    return *this;

} // operator = ()

// Suite question 7

inline CHistogramme & CHistogramme::operator + (const unsigned int Nbre) throw ()
{
    Ajouter (Nbre);

    return *this;

} // operator + ()

// Suite question 8

inline CHistogramme & CHistogramme::operator +
               (const CHistogramme & Histogramme) throw (exception)
{
    if (m_Etendue != Histogramme.m_Etendue) throw exception  ();

    if (m_Effectif.size () < Histogramme.m_Effectif.size ())
        m_Effectif.resize (Histogramme.m_Effectif.size ());

    for (int i = 0; i < m_Effectif.size (); ++i)
        m_Effectif [i] += Histogramme.m_Effectif [i] ;

    m_EffTotal += Histogramme.m_EffTotal;

    return *this;

} // operator + ()

int main (void)
{
    CHistogramme Hist1 (3);
    CHistogramme Hist2;
    CHistogramme Hist3 (Hist1);
    cout << "Hist1 - \n"; Hist1.Afficher (); cout << endl;
    cout << "Hist2 - \n"; Hist2.Afficher (); cout << endl;
    cout << "Hist3 - \n"; Hist3.Afficher (); cout << endl;

    Hist1.Ajouter (10);
    Hist1.Ajouter (3);
    Hist1.Ajouter (16);
    for (int i = 0; i < 5; ++i) Hist1.Ajouter (10);

    cout << "Hist1 - \n"; Hist1.Afficher(); cout << endl;
 
    Hist1.Supprimer (10);
    Hist1.Supprimer (16);
    Hist1.Supprimer (10);
    Hist1.Supprimer (3);

    cout << "Hist1 - \n"; Hist1.Afficher(); cout << endl;
    cout << "Hist1 - \n" << Hist1 << endl;
 
    Hist2 = Hist2 = Hist1 = Hist1;

    Hist1 = Hist1 + 2;
    Hist1 = Hist1 + 2;

    Hist2.Ajouter (16);

    cout << "Hist1 - \n" << Hist1 << endl;
    cout << "Hist2 - \n" << Hist2 << endl;
 
    cout << "Hist1 + Hist2 - \n" << Hist1 + Hist2 << endl;

    try
    {
        CHistogramme Hist (0);
    }
    catch (const exception & e)
    {
        cerr << "Exception ; etendue nulle" << endl;
    }
    try
    {
        Hist1.Supprimer (12);
    }
    catch (const exception & e)
    {
        cerr << "Exception : suppression invalide" << endl;
    }
    try
    {
        Hist1.Supprimer (30);
    }
    catch (const exception & e)
    {
        cerr << "Exception : suppression invalide" << endl;
    }
    try
    {
        CHistogramme Hist4 (4);
        Hist4 = Hist4 + Hist1;
    }
    catch (const exception & e)
    {
        cerr << "Exception : etendues incompatibles" << endl;
    }
    try
    {
        CHistogramme Hist4 (4);
        Hist1 = Hist1 + Hist4;
    }
    catch (const exception & e)
    {
        cerr << "Exception : etendues incompatibles" << endl;
    }

    return 0;

} // main()