Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Comment structurer son projet C++ ?

IUT d'Orsay, Université Paris-Saclay

Un exemple d’un début de projet :

project/
└── main.cpp
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>

class Student {
private:
    std::string mName;
    int mId;

public:
    Student(std::string name, int id) {
        mName = name;
        mId = id;
    }

    std::string getName() const {
        return mName;
    }

    int getId() const {
        return mId;
    }
};

class Group {
private:
    std::string mName;
    std::vector<Student> mStudents;

public:
    Group(std::string name) {
        mName = name;
    }

    std::string getName() const {
        return mName;
    }

    const std::vector<Student>& getStudents() const {
        return mStudents;
    }

    void addStudent(const Student& student) {
        //...
    }

    int getStudentCount() const {
        //...
    }
};

class Room {
private:
    std::string mName;
    int mCapacity;

public:
    Room(std::string name, int capacity) {
        mName = name;
        mCapacity = capacity;
    }

    std::string getName() const {
        return mName;
    }

    int getCapacity() const {
        return mCapacity;
    }
};

void displayStudent(const Student& student) {
    //...
}

void displayGroup(const Group& group) {
    //...
}

void displayRoom(const Room& room) {
    //...
}

void assignStudentToGroup(Group& group, const Student& student) {
    //...
}

void assignGroupToRoom(Group& group, Room& room) {
    //...
}


int main() {
    //...
    return 0;
}

Découpage du code

Une première séparation (non fonctionnelle)

Nous pouvons d’abord séparer le code en plusieurs fichiers comme ceci.

project/
├── student.cpp
├── group.cpp
├── room.cpp
├── display.cpp
├── assignment.cpp
└── main.cpp
student.cpp
group.cpp
room.cpp
display.cpp
assignment.cpp
main.cpp
class Student {
private:
    std::string mName;
    int mId;

public:
    Student(std::string name, int id) {
        mName = name;
        mId = id;
    }

    std::string getName() const {
        return mName;
    }

    int getId() const {
        return mId;
    }
};

Par exemple, Group a besoin de Student ainsi que main pour fonctionner.

Nous pouvons être tenté de faire la chose suivante :

group.cpp
main.cpp
#include "student.cpp"

// Contenu de group.cpp

Lors de la compilation, le contenu des fichiers .cpp deviennent :

group.cpp
main.cpp
// #include "student.cpp" devient :
// Contenu de student.cpp

// Contenu de group.cpp

Comment les bibliothèques de C++ évitent ce problème ?

Header et source

La réponse est de séparer la déclaration et l’implémentation des objets :

project/
├── include/
│    ├── student.h
│    ├── group.h
│    ├── room.h
│    ├── display.h
│    └── assignment.h
└── source/
    ├── student.cpp
    ├── group.cpp
    ├── room.cpp
    ├── display.cpp
    ├── assignment.cpp
    └── main.cpp

Les headers :

student.h
group.h
room.h
display.h
assignment.h
#ifndef STUDENT_H
#define STUDENT_H

#include <string>
class Student {
private:
    std::string mName;
    int mId;

public:
    Student(std::string name, int id);
    std::string getName() const;
    int getId() const;
};

#endif

Les codes sources :

student.cpp
group.cpp
room.cpp
display.cpp
assignment.cpp
main.cpp
#include "student.h"

Student::Student(std::string name, int id) {
    mName = name;
    mId = id;
}

std::string Student::getName() const {
    return mName;
}

int Student::getId() const {
    return mId;
}

Pour aller plus loin

Un exemple de structure MVC :

project/
├── include/
│   ├── model/
│   │   ├── student.h
│   │   ├── group.h
│   │   └── room.h
│   ├── view/
│   │   ├── student-view.h
│   │   ├── group-view.h
│   │   └── room-view.h
│   └── controller/
│       ├── group-controller.h
│       └── room-controller.h
└── source/
    ├── model/
    │   ├── student.cpp
    │   ├── group.cpp
    │   └── room.cpp
    ├── view/
    │   ├── student-view.cpp
    │   ├── group-view.cpp
    │   └── room-view.cpp
    ├── controller/
    │   ├── group-controller.cpp
    │   └── room-controller.cpp
    └── main.cpp

Compilation automatique

project/
└── main.cpp

D’habitude, nous compilons notre seul fichier de code directement en exécutable avec

g++ main.cpp -o executable

Nous pouvons aussi utiliser un makefile pour simplifier les commandes de compilation, d’exécution, et de nettoyage à :

make
make run
make clean
project/
├── main.cpp
└── makefile
makefile
all: executable

executable:
    g++ main.cpp -o executable

run:
    ./executable

clean:
    rm -f executable

.PHONY: all run clean

Nous allons séparer la compilation en translation unit (.o) et le linking.

makefile
all: executable

executable: main.o
	g++ main.o -o executable

main.o: main.cpp
	g++ -c main.cpp -o main.o

run: executable
	./executable

clean:
	rm -f main.o executable

.PHONY: all run clean

Les makefiles pour les projets plus complexes seront vus en TP !