C++: Correction MaString

 

1 Interface de la classe MaString

Voici l'entête de la classe donné dans l'énoncé : 

 

#ifndef __MASTRING_H__
#define __MASTRING_H__

#include <stddef.h>
#include <ostream.h>
#include <stdio.h>

const size_t MaStringMax = 1024;

class MaString {
  friend ostream & operator << (ostream &, const MaString &);

public:
  enum caseCompare  {exact, ignoreCase};

  MaString();              
  MaString(const MaString & S);
  MaString(const char * a);   
  MaString(char c);
  ~MaString();

  int          compareTo(const MaString &, caseCompare cmp = exact) const;
  void         copyFrom(const MaString & s); // copie de la chaine s
  MaString     copy() const; // retourne une copie
  const char * c_str() const; // le buffer 
  size_t       size() const; // la longueur
  MaString&    prepend(const char* cs); // insertion en tete cs
  MaString&    prepend(const char* cs, size_t N); // insertion en tete de N car. depuis cs
  MaString&    prepend(const MaString& s); // insertion en tete s
  MaString&    prepend(const MaString& s, size_t N); // insertion en tete de N car. depuis s
  MaString&    append(const char*); // ajout de cs
  MaString&    append(const char* cs, size_t N); // ajout de N car. depuis cs
  MaString&    append(const MaString& s); // ajout de s
  MaString&    append(const MaString& s, size_t N); // ajout de N car. depuis s
  MaString&    append(char); // ajout d'un caractere

private:
  char data_[MaStringMax]; // un buffer de taille fixe
};
#endif /* __MASTRING_H__ */

 

 

2 Mise en oeuvre de la classe

Voici une mise en œuvre de la classe MaString : 

 

#include <assert.h>
#include "mastring.hh"
#include "string.h"

// Pour la gestion de data_, on considère la constante suivante :
// data_ est géré comme une chaine C, le dernier caractère est toujours
// suivi par '\0'.

ostream & operator << (ostream & out, const MaString & s)
{
  out << s.data_;
}

MaString::
MaString()
{
  data_[0] = 0; // Initialisation à chaine vide 
}

// Constructeur par copie : on copie le data_ de S
// dans this->data_
MaString::
MaString(const MaString& S)
{
  assert(S.size() < MaStringMax);
  strcpy(data_, S.data_);
}

// Constructeur par cousinage : on copie a dans
// this->data_
MaString::
MaString(const char * a)
{
  assert(strlen(a) < MaStringMax);
  strcpy(data_, a);
}

// Constructeur par cousinage : on copie c
// this->data_[0] et on n'oublie pas le `\0`
// de fin de chaine en this->data_[1]
MaString::
MaString(char c)
{
  data_[0] = c;
  data_[1] = 0;
}

// Rien à faire car data_ est un tableau C
// aucune variable membre n'a besoin d'etre
// libérée
MaString::
~MaString()
{
}

// Comparaison "à la C" en tenant compte ou non des 
// différences minuscules/majuscules
int MaString::
compareTo(const MaString & st, caseCompare cmp) const
{
  if (cmp == exact) {
    return strcmp(data_, st.data_);
  } else {
    return strcasecmp(data_, st.data_);
  }
}

// Un MaString existant copie un autre MaString
// Ici c'est comme un constructeur par copie, mais
// attention, en général, ce n'est pas le cas
void MaString::
copyFrom(const MaString& st)
{
  assert(st.size() < MaStringMax);
  strcpy(data_, st.data_);
}

// clonage (inutile si ce n'est pour
// discuter de this)
MaString MaString::
copy() const
{
  return *this;
}

// un accesseur en lecture
const char*  MaString::
c_str() const 
{
  return data_;
}

size_t MaString::
size() const
{
  return strlen(data_);
}

// Ajouter en tete N caracteres de cs.
// On passe par un buffer pour sauvegarder data_;
MaString& MaString::
prepend(const char* cs, size_t N)
{
  assert(N + size() < MaStringMax);
  MaString tmp(data_);
  strncpy(data_, cs, N);
  data_[N] = 0;
  strcat(data_, tmp.data_);
  return *this;
}

// On peut réutiliser un autre version de prepend
MaString& MaString::
prepend(const char* cs)
{
  assert(strlen(cs) + size() < MaStringMax);
  prepend(cs, strlen(cs));
  return *this;
}

// On peut réutiliser un autre version de prepend
MaString& MaString::
prepend(const MaString& s)
{  
  prepend(s.data_);
  return *this;
}

// On peut réutiliser un autre version de prepend
MaString& MaString::
prepend(const MaString& s, size_t N)
{
  prepend(s.data_, strlen(s.data_));
  return *this;
}

// Concaténation de chaine toute simple
MaString& MaString::
append(const char* cs)
{
  assert(size() + strlen(cs) < MaStringMax);
  strcat(data_, cs);
}

// Concaténation de chaine un tout petit peu plus compliquée
MaString& MaString::
append(const char* cs, size_t N)
{
  assert(size() + N < MaStringMax);
  strncat(data_, cs, N);
  return *this;
}

// On peut réutiliser un autre version de append
MaString& MaString::
append(const MaString& s)
{
  append(s.data_);
  return *this;
}

// On peut réutiliser un autre version de append
MaString& MaString::
append(const MaString& s, size_t N)
{
  append(s.data_, N);
  return *this;
}

// On peut réutiliser un autre version de append
MaString& MaString::
append(char c)
{
  assert(size() + 1 < MaStringMax);
  char s[2];
  s[0] = c;
  s[1] = 0;
  append(s);
  return *this;
}