Most online C++ compilers give you one editor, and one editor means one file. That's fine until your course splits a class into Student.h and Student.cpp. Then the second line of main.cpp stops the build:
code.cc:2:10: fatal error: Student.h: No such file or directory 2 | #include "Student.h" | ^~~~~~~~~~~ compilation terminated. Here's why that happens, three ways around it, and the linker errors you'll meet on the way.
Why the include fails
#include "Student.h" tells the compiler to read Student.h from the folder of the file that includes it. A one-file online compiler saves your code on its own in an empty folder, so there is no Student.h to read.
Pasting in just the header doesn't fix it either. The header only declares the class; the member functions are defined in Student.cpp. If that file isn't compiled too, the linker stops instead:
/usr/bin/ld: /tmp/ccdg4WQe.o: in function `main': code.cc:(.text.startup+0x33): undefined reference to `Student::Student(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)' ... collect2: error: ld returned 1 exit status The program needs both files, compiled and linked together.
The example
A small class, split the usual way:
// Student.h #ifndef STUDENT_H #define STUDENT_H #include <string> class Student { public: Student(const std::string& name, int score); std::string name() const; bool passed() const; private: std::string name_; int score_; }; #endif // Student.cpp #include "Student.h" Student::Student(const std::string& name, int score) : name_(name), score_(score) {} std::string Student::name() const { return name_; } bool Student::passed() const { return score_ >= 50; } // main.cpp #include <iostream> #include "Student.h" int main() { Student ada("Ada", 91); Student tim("Tim", 42); std::cout << ada.name() << (ada.passed() ? " passed" : " failed") << "\n"; std::cout << tim.name() << (tim.passed() ? " passed" : " failed") << "\n"; } On your own computer you build both .cpp files into one program:
g++ main.cpp Student.cpp -o main ./main Ada passed Tim failed Option 1: paste the class above main
This works in any online compiler. Put the class declaration and its member functions in the same file, above main, and drop the #include "Student.h" line. It's fine for a quick check, but you lose the very structure your course is trying to teach, and it doesn't scale past one or two classes.
Option 2: use an online IDE with projects
If you want to click Run in a browser with a tab per file, use a tool that has projects. OnlineGDB lets you add files to a project (and has a debugger), Playcode handles .cpp and .h files in folders, and Replit builds every C++ file in a project into one program. Check each one's current plans and limits yourself.
Option 3: send the files to a compiler API
If the code comes from a script, a course platform or an autograder rather than a person typing in a browser, send the files with the program. OnlineCompiler.io's API (which I build) takes main.cpp as the program and every other file in a files list:
curl -X POST https://api.onlinecompiler.io/api/run-code-sync/ \ -H "Authorization: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "compiler": "g++-15", "code": "#include <iostream>\n#include \"Student.h\"\n\nint main() {\n Student ada(\"Ada\", 91);\n Student tim(\"Tim\", 42);\n std::cout << ada.name() << (ada.passed() ? \" passed\" : \" failed\") << \"\\n\";\n std::cout << tim.name() << (tim.passed() ? \" passed\" : \" failed\") << \"\\n\";\n}\n", "files": [ {"name": "Student.h", "content": "#ifndef STUDENT_H\n#define STUDENT_H\n\n#include <string>\n\nclass Student {\npublic:\n Student(const std::string& name, int score);\n std::string name() const;\n bool passed() const;\n\nprivate:\n std::string name_;\n int score_;\n};\n\n#endif\n"}, {"name": "Student.cpp", "content": "#include \"Student.h\"\n\nStudent::Student(const std::string& name, int score) : name_(name), score_(score) {}\n\nstd::string Student::name() const { return name_; }\n\nbool Student::passed() const { return score_ >= 50; }\n"} ] }' The response's output is Ada passed\nTim failed\n and exit_code is 0. What happens on the server:
- Every
.cpp,.ccand.cxxfile you send is compiled and linked with the program, here asg++ -O2 -Wall code.cc Student.cpp -o code.out. - Headers aren't compiled on their own; they're read where a file includes them.
- The
namemust match your#includeexactly, capital letters included:student.his notStudent.h. - Folders work (
lib/Student.h), up to 20 files and 1 MB besides the program. -
g++-15is C++17; useg++-15-cpp20for C++20. Add"input"when the program reads fromcin.
The same thing from Python, reading the files from the folder you run it in:
from pathlib import Path import requests files = ["Student.h", "Student.cpp"] response = requests.post( "https://api.onlinecompiler.io/api/run-code-sync/", headers={"Authorization": "YOUR_API_KEY"}, json={ "compiler": "g++-15", "code": Path("main.cpp").read_text(), "files": [{"name": name, "content": Path(name).read_text()} for name in files], }, timeout=60, ) result = response.json() print(result["output"], end="") print(result["error"], end="") print("exit code:", result["exit_code"]) What if your course says #include "Student.cpp"?
Some courses have main.cpp include the .cpp file instead of the header, so the class arrives with its code in one step. Change the include and send the same two files: it prints the same output. The rule that makes both styles work is that a file included with #include "..." is compiled only through that include, never again on its own, so each function is compiled exactly once.
On your own computer the two styles need different commands. With the header, build both files (g++ main.cpp Student.cpp). With #include "Student.cpp", build only g++ main.cpp. Build both in that style and the class is compiled twice, which the linker refuses (shortened):
$ g++ main.cpp Student.cpp -o main /usr/bin/ld: /tmp/cciho97q.o: in function `Student::Student(...)': Student.cpp:(.text+0x0): multiple definition of `Student::Student(...)'; /tmp/ccteijRb.o:main.cpp:(.text+0xb0): first defined here collect2: error: ld returned 1 exit status An IDE that builds every .cpp file in a project does exactly that, so there, include the header. Headers are how larger C++ programs are built anyway.
The errors, in one table
| Error | What it means | Fix |
|---|---|---|
fatal error: Student.h: No such file or directory | The header isn't next to the program, or its name differs (case counts) | Add it under the exact name you include |
undefined reference to `Student::Student(...)' | The header was found, but nothing defines the functions it declares | Compile and link Student.cpp too |
redefinition of 'class Student' | One file read the header twice, and it has no include guard | Wrap it in #ifndef STUDENT_H / #define STUDENT_H / #endif, or use #pragma once |
multiple definition of `passMark()' | A function body lives in a header that two .cpp files include | Move the body to the .cpp, or mark it inline |
multiple definition of `main' | A second file (often a .cpp with a leftover test main) defines main | Keep one main |
Grading multi-file C++ automatically
If you teach, the same files list works with the API's run-tests endpoint: send the student's Student.cpp, your own main.cpp that exercises it, and a list of inputs with expected outputs, and you get a verdict for each test and a score. That's how you can auto-grade a class assignment without setting up a judge server. The free plan has 100,000 runs a month, no credit card.
The full guide, with every output and the C, Java and folder variations, is here: C++ header files in an online compiler.
Disclosure: I build OnlineCompiler.io. Options 1 and 2 above work without it.

![Path Planning and Autonomous Navigation — Ch.11: Towing AMR Navigation [EN]](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyvsxdf311sqylulf87m4.png)