Reputation: 63
So I'm back again. I'm not sure if there is a limit to how many questions we can ask in a day so I'm sorry if I'm asking too much but I have a project to do and no more class periods to ask the professor so I'm turning to you guys.
Anyway, my problem is with overloading the input and output operators. I feel like I have it done right but I'm getting a linker error that I don't know how to resolve. It's probably a simple mistake but here goes.
Can anyone tell me what I did this time? Thanks in advance for any help you can give me.
Edit: here is some more information. I'm using Visual Studio 2010 and as far as I know I haven't changed anything about the library dependencies but it is a possibility. Here is my entire header file which contains all of my code for this class: in the file FixedStr.h
#ifndef FIXEDSTR_H
#define FIXEDSTR_H
#include <string>
#include <iostream>
using namespace std;
template <int N>
class FixedStr
{
public:
FixedStr ();
FixedStr (const FixedStr<N> &);
FixedStr (const string &);
~FixedStr ();
FixedStr<N> & Copy (const FixedStr<N> &);
FixedStr<N> & Copy (const string &);
int Size (const FixedStr<N> &);
FixedStr<N> & operator = (const FixedStr<N> &);
FixedStr<N> & operator = (const string &);
char operator [] (int);
const char operator [] (int) const;
friend ostream & operator << (ostream &, const FixedStr<N> &);
private:
string Data;
};
template <int N>
FixedStr<N>::FixedStr ()
{
}
template <int N>
FixedStr<N>::~FixedStr ()
{
}
template <int N>
FixedStr<N>::FixedStr (const FixedStr<N> & FStr)
{
Data = FStr.Data;
}
template <int N>
FixedStr<N>::FixedStr (const string & Str)
{
if (Str.length() == N)
Data = Str;
}
template <int N>
inline FixedStr<N> & FixedStr<N>::Copy (const FixedStr<N> & F)
{
Data = F.Data;
return *this;
}
template <int N>
inline FixedStr<N> & FixedStr<N>::Copy (const string & Str)
{
if (Str.length() == N)
Data = Str;
}
template <int N>
inline FixedStr<N> & FixedStr<N>::operator= (const FixedStr<N> & F)
{
return Copy (F);
}
template <int N>
inline FixedStr<N> & FixedStr<N>::operator= (const string & Str)
{
return Copy (Str);
}
template <int N>
inline int FixedStr<N>::Size (const FixedStr<N> &)
{
return N;
}
template <int N>
inline char FixedStr<N>::operator[] (int i)
{
return Data[i];
}
template <int N>
inline const char FixedStr<N>::operator[] (int i) const
{
return Data[i];
}
template <int N>
ostream & operator << (ostream & out, const FixedStr<N> & F)
{
return out << F.Data;
}
#endif
Here is the error: Main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class FixedStr<5> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$FixedStr@$04@@@Z) referenced in function _main
And here is the main I am testing it with: In the file Main.cpp
using namespace std;
#include "FixedStr.h"
#include "DigitStr.h"
void main ()
{
string Str = "12345";
FixedStr<5> FStr1 (Str);
DigitStr<5> DStr;
DStr.Copy (FStr1);
DStr.Copy (Str);
cout << FStr1;
}
There is also a child class called DigitStr.h which look like this:
#ifndef DIGITSTR_H
#define DIGITSTR_H
#include <cctype>
#include "FixedStr.h"
template <int N>
class DigitStr: public FixedStr<N>
{
public:
enum Exceptions {NON_DIGIT_EXCEPTION};
DigitStr ();
DigitStr (const DigitStr &);
DigitStr (const FixedStr<N> &);
DigitStr (const string &);
~DigitStr ();
DigitStr<N> & Copy (const FixedStr<N> &);
DigitStr<N> & Copy (const string &);
private:
};
template <int N>
DigitStr<N>::DigitStr ()
{
}
template <int N>
DigitStr<N>::DigitStr (const DigitStr & DStr): FixedStr (DStr)
{
}
template <int N>
DigitStr<N>::DigitStr (const FixedStr<N> & FStr): FixedStr (FStr)
{
for (int i=0; i<N; i++)
{
if (isdigit(FStr[i]) == 0)
throw NON_DIGIT_EXCEPTION;
else;
}
}
template <int N>
DigitStr<N>::DigitStr (const string & Str): FixedStr (Str)
{
for (int i=0; i<N; i++)
{
if (isdigit(Str[i]) == 0)
throw NON_DIGIT_EXCEPTION;
else;
}
}
template <int N>
DigitStr<N>::~DigitStr ()
{
}
template <int N>
DigitStr<N> & DigitStr<N>::Copy (const FixedStr<N> & FStr)
{
for (int i=0; i<N; i++)
{
if (isdigit(FStr[i]) == 0)
throw NON_DIGIT_EXCEPTION;
else;
}
*this = FStr;
return *this;
}
template <int N>
DigitStr<N> & DigitStr<N>::Copy (const string & Str)
{
for (int i=0; i<N; i++)
{
if (isdigit(Str[i]) == 0)
throw NON_DIGIT_EXCEPTION;
else;
}
*this = Str;
return *this;
}
#endif
Also I do not know what compilation commands are yet. I have simply been going into the project menu and doing Compile and then when that finishes Build under the Build menu on VS 2010.
Edit: I also tried resetting all of my setting in Visual Studio to no avail. The problem seems to be with just the definition and not the actual method as commenting out the method does not get rid of the problem.
Upvotes: 0
Views: 1601
Reputation: 26409
Replace
friend ostream& operator<< (ostream &, const FixedStr<N> &);
With
template<int N> friend ostream& operator<< (ostream &, const FixedStr<N> &);
Upvotes: 2
Reputation: 3290
Where is your main function?
Your code seems correct. It compiles without any error on my machine.
You may want to check at the library that you are linking against. If you use Visual studio to compile, the default setup should have correct libraries unless you have tampered with the properties of the IDE.
In case of linker errors which I cannot resolve, I usually use a tool called Depends.exe which identifies the library it cannot find. Once the library is located and appropriate paths added in your project, you should be able to compile it properly.
Upvotes: 0
Reputation: 61519
Template function definitions like that can't be defined in a separate translation unit. This is an annoying limitation of how C++ templates work. There is an export
keyword that is supposed to help, but it doesn't actually do what it seems like it's supposed to.
Either put the definition of the operator<<
into the header file directly (this is fine and will not cause multiple symbol definition errors, again because of how templates work), or put it there indirectly by #include
ing it from another file (don't give it a .cpp
file ending, for organizational purposes - although the compiler doesn't really care about your file extensions; by convention, most people use .i
or .inl
for such a file).
By the way, the type std::string
does not come from <string.h>
. That is a C header. It comes from <string>
. If it's working for you, it's only by coincidence (many implementations of <iostream>
include <string>
. Also, consider using <iosfwd>
instead of <iostream>
in header files to improve compile times (although that won't really help you here, since you need the full <iostream>
header for the template implementation).
Upvotes: 0