Reflection on Duplicate Symbols: A C++ Include Mishap
I was coding away on a simple C++ project—a TextBox class with getter and setter function, nothing fancy. I compile it, expecting a clean run, and the terminal spits out a cryptic error:
1 | duplicate symbol 'TextBox::setValue(...)' in: |
Duplicate symbols? Linker errors? What did I do wrong? If this sounds familiar, buckle up—I’m about to share the debugging experience that taught me a golden rule of C++: never #include a .cpp file.
The Problem: A Rookie Mistake
My project was straightforward. I had three files:
TextBox.h: The header declaring myTextBoxclass.TextBox.cpp: The implementation of the class methods.main.cpp: A simple test program to create aTextBoxobject and call its methods.
In main.cpp, I wrote:
1 |
|
1 |
|
TextBox.h looks like
1 |
|
And TextBox.cpp held the implementation:
1 |
|
The First Fix Try with Include Guard
Firstly, I thought it may be due to the manually inputted include guard didn’t like CLION-style. So I do the following try:
My main.cpp and TextBox.cpp stayed the same.
I changed TextBox.h ‘s include guard’:
1 |
|
With this setup, I compiled it again: g++ TextBox.cpp main.cpp -o myProgram. Still errors!
Final Try and True Reason
I fixed the bug by changing hash-include part in main.cpp file, I changed #include "TextBox.cpp" into #include "TextBox.h".
In C++, header files (.h) are for declarations, and source files (.cpp) are for definitions. Our #include the header to tell other files what’s available, then let the linker combine the implementations.
By including TextBox.cpp in main.cpp, I was telling the compiler to dump the entire implementation—getValue() and setValue()—into main.cpp. Then, the compiler also compiled TextBox.cpp separately. This created two object files (main.o and TextBox.o), both containing the same function definitions. When the linker tried to stitch them together, it found duplicates and threw a tantrum.
Extra Lessons: Include Guards Rules
I picked up a few bonus lessons along the way:
Include Guard Matters ??? It doesn’t matter: That #ifndef TEXTBOX_H and #define TEXTBOX_H in my header? It’s an include guard, ensuring the file isn’t processed multiple times in one compilation. The name doesn’t matter much—as long as it’s unique across the project and matches within the file. I could’ve used FOO, but ADVANCED_TEXTBOX_H that ties it to my file with a CLION style reducing collision risks.
Conclusion
Always separate declarations (in .h) from implementations (in .cpp), and never #include a .cpp file. It’s a simple rule, but violating it sent me down a rabbit hole of duplicate symbols and linker woes.
- Title: Reflection on Duplicate Symbols: A C++ Include Mishap
- Author: Ricardo Pu
- Created at : 2025-04-09 16:28:41
- Updated at : 2025-04-09 16:51:17
- Link: https://ricardopotter.github.io/RicardoBlog/2025/04/09/Reflection-on-Duplicate-Symbols-A-CPP-Include-Mishap/
- License: This work is licensed under CC BY-NC-SA 4.0.