自定义fstream扩展类调用函数时出现未定义引用链接错误求助
fstreamExtension: Fixes & Code Optimization Alright, let's break down why you're seeing those "undefined reference" errors and walk through solutions, plus some tips to improve your code structure.
First, here's your existing code for context:
fstreamExtension.h
#include <fstream> #include <string> #include <vector> #ifndef FSTREAMEXTENSION_H #define FSTREAMEXTENSION_H class fstreamExtension : public std::fstream { private: std::string fileIdentifier; public: using std::fstream::fstream; using std::fstream::open; ~fstreamExtension(); inline void fileName (std::string&); inline bool exists (); inline unsigned long long fileSize(); }; #endif
fstreamExtension.cpp
#include <iostream> #include <fstream> #include <string> #include <vector> #include "fstreamExtension.h" inline void fstreamExtension::fileName (std::string& __fileIdentifier) { fileIdentifier = __fileIdentifier; } inline bool fstreamExtension::exists () { if (FILE *file = fopen(fileIdentifier.c_str(), "r")) { fclose(file); return true; } else return false; } inline unsigned long long int fstreamExtension::fileSize() { if(exists()) { std::ifstream tempStream(fileIdentifier.c_str(), std::ios::ate | std::ios::binary); unsigned long long int __size = tempStream.tellg(); tempStream.close(); return __size; } else return 0; } fstreamExtension::~fstreamExtension() { std::fstream::close(); std::cout << "stream closed"; }
Main Implementation
#include <iostream> #include <fstream> #include "fstreamExtension.h" int main() { string s = "QBFdata.txt"; fstreamExtension fs(s.c_str(), ios::in | ios::binary); fs.fileName(s); //error cout << fs.fileSize(); //error }
The Error You're Seeing
undefined reference to fstreamExtension::fileName(std::string&)
Root Cause: Misplaced inline Functions
In C++, inline functions require their full definition to be visible in every compilation unit that uses them. You declared the functions as inline in the header, but put their implementation in a .cpp file. When the compiler builds main.cpp, it can't see the actual code for those inline functions, so the linker ends up missing them.
Fix Options
You have two straightforward ways to resolve this:
Option 1: Move inline Function Definitions to the Header
Put the function bodies directly in the header (either inside the class or outside it, as long as they're in the header). This makes the definition visible to all compilation units.
Updated fstreamExtension.h:
#include <fstream> #include <string> #include <vector> #include <cstdio> // Required for fopen/fclose #ifndef FSTREAMEXTENSION_H #define FSTREAMEXTENSION_H class fstreamExtension : public std::fstream { private: std::string fileIdentifier; public: using std::fstream::fstream; using std::fstream::open; ~fstreamExtension(); // Implement inline functions directly in the class inline void fileName(std::string& name) { fileIdentifier = name; } inline bool exists() { if (FILE* file = fopen(fileIdentifier.c_str(), "r")) { fclose(file); return true; } return false; } inline unsigned long long fileSize() { if (exists()) { std::ifstream tempStream(fileIdentifier.c_str(), std::ios::ate | std::ios::binary); unsigned long long size = tempStream.tellg(); tempStream.close(); return size; } return 0; } }; #endif
Then simplify fstreamExtension.cpp to only contain the destructor:
#include <iostream> #include "fstreamExtension.h" fstreamExtension::~fstreamExtension() { std::fstream::close(); std::cout << "stream closed"; }
Option 2: Remove the inline Keyword
If you don't need these functions to be inline, just drop the inline specifier from both the header declarations and the .cpp implementations. The linker will then find the definitions normally.
Updated fstreamExtension.h:
#include <fstream> #include <string> #include <vector> #ifndef FSTREAMEXTENSION_H #define FSTREAMEXTENSION_H class fstreamExtension : public std::fstream { private: std::string fileIdentifier; public: using std::fstream::fstream; using std::fstream::open; ~fstreamExtension(); void fileName(std::string&); bool exists(); unsigned long long fileSize(); }; #endif
Updated fstreamExtension.cpp:
#include <iostream> #include <fstream> #include <string> #include <vector> #include <cstdio> #include "fstreamExtension.h" void fstreamExtension::fileName(std::string& file_name) { fileIdentifier = file_name; } bool fstreamExtension::exists() { if (FILE* file = fopen(fileIdentifier.c_str(), "r")) { fclose(file); return true; } return false; } unsigned long long fstreamExtension::fileSize() { if (exists()) { std::ifstream tempStream(fileIdentifier.c_str(), std::ios::ate | std::ios::binary); unsigned long long size = tempStream.tellg(); tempStream.close(); return size; } return 0; } fstreamExtension::~fstreamExtension() { std::fstream::close(); std::cout << "stream closed"; }
Code Optimization Tips
Let's make your code cleaner, safer, and more efficient:
Avoid Reserved Names
Names starting with double underscores (__fileIdentifier) are reserved for the compiler and standard library. Use regular names likefile_nameoridentifierinstead to avoid conflicts.Fix Namespace Issues in Main
Your main code usesstringandcoutwithout thestd::prefix. Either addstd::before them, or addusing namespace std;at the top ofmain.cpp(note: avoidusing namespace std;in headers).Reuse the Existing Stream for File Size
Instead of creating a newstd::ifstreaminfileSize(), use the inheritedstd::fstreamif it's already open. This saves you from opening the file twice:unsigned long long fileSize() { if (this->is_open()) { // Save current position std::streampos current_pos = this->tellg(); // Jump to end to get size this->seekg(0, std::ios::end); unsigned long long size = this->tellg(); // Restore original position this->seekg(current_pos); return size; } // Fallback to opening a new stream if needed if (exists()) { std::ifstream tempStream(fileIdentifier.c_str(), std::ios::ate | std::ios::binary); unsigned long long size = tempStream.tellg(); tempStream.close(); return size; } return 0; }Simplify the Destructor
std::fstream's destructor automatically closes the file, so you don't need to callstd::fstream::close()manually. Remove that line to avoid redundant work.Use
constReferences for Input Parameters
YourfileName()function doesn't modify the input string, so make it aconstreference. This allows it to accept temporary strings and is safer:void fileName(const std::string& name) { fileIdentifier = name; }Add a Constructor to Initialize
fileIdentifier
Avoid needing to callfileName()separately by adding a constructor that setsfileIdentifierwhen you create the object:// Add this to the public section of fstreamExtension in the header fstreamExtension(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::fstream(filename, mode), fileIdentifier(filename) {}Now your main can be simplified to:
int main() { std::string s = "QBFdata.txt"; fstreamExtension fs(s, std::ios::in | std::ios::binary); std::cout << fs.fileSize(); return 0; }
内容的提问来源于stack exchange,提问作者Nilesh Kumar

