Why can't the linker find the definitions?

W

William Payne

Hello, I am toying with a simple string class I wrote quite some time ago. I
noticed that if I try to use operator == or != I get undefiend references,
but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

The code that triggers these undefined references is simply:
if(str == s2)
{
cout << "s2 == str" << endl;
}
else
{
cout << "s2 != str" << endl;
}

if(str != s2)
{
cout << "s2 != str" << endl;
}
else
{
cout << "s2 == str" << endl;
}

where str and s2 is of type String (my string class).

And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

what am I missing?

Thanks for any replies!

/ WP
 
D

David Hilsee

William Payne said:
Hello, I am toying with a simple string class I wrote quite some time ago. I
noticed that if I try to use operator == or != I get undefiend references,
but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}
<snip>

Functions that are declared inline have internal linkage and should be
defined in the header. Move these to the header file. If you need a
helpful reminder as to why, just remember that "inline" means that the
programmer wishes to have the code "pasted" into the caller's source, so the
compiler needs to "see" it when compiling other implementation files.
 
J

John Harrison

William Payne said:
Hello, I am toying with a simple string class I wrote quite some time ago.
I noticed that if I try to use operator == or != I get undefiend
references, but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

Why are they declared inline if they are in the implementation file?

inline functions go in the header file, non-inline functions go in the
implementation file.

[snip]
And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

Hard to say without seeing the rest of the code. What is c declared as? What
is String::eek:perator[] declared as?

john
 
W

William Payne

John Harrison said:
William Payne said:
Hello, I am toying with a simple string class I wrote quite some time
ago. I noticed that if I try to use operator == or != I get undefiend
references, but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

Why are they declared inline if they are in the implementation file?

inline functions go in the header file, non-inline functions go in the
implementation file.

[snip]
And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

Hard to say without seeing the rest of the code. What is c declared as?
What is String::eek:perator[] declared as?

john

Thanks for the quick reply, both of you. I just noticed that it was indeed
my use of inline in the .cpp-file that was the culprit of the linking
errors. For some reason I thought that any function defined in the header
file would be inlined automatically and that I could use the keyword inline
to request functions defined in the implementation file (cpp-file) to be
inlined as well, provided they were short enough. So if I want to request a
function to be inlined, it must be defined in the header? Inside the class
declaration itself or can it be outside (but still in the header)?

c is of type char, sorry, should've posted that.
and operator[] is declared as:
char operator[](std::size_t index) const;

I need two versions, one non-const?

/ WP
 
D

David Hilsee

William Payne said:
John Harrison said:
William Payne said:
Hello, I am toying with a simple string class I wrote quite some time
ago. I noticed that if I try to use operator == or != I get undefiend
references, but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

Why are they declared inline if they are in the implementation file?

inline functions go in the header file, non-inline functions go in the
implementation file.

[snip]
And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

Hard to say without seeing the rest of the code. What is c declared as?
What is String::eek:perator[] declared as?

john

Thanks for the quick reply, both of you. I just noticed that it was indeed
my use of inline in the .cpp-file that was the culprit of the linking
errors. For some reason I thought that any function defined in the header
file would be inlined automatically and that I could use the keyword inline
to request functions defined in the implementation file (cpp-file) to be
inlined as well, provided they were short enough. So if I want to request a
function to be inlined, it must be defined in the header? Inside the class
declaration itself or can it be outside (but still in the header)?

Member functions that are defined inside the class definition are implicitly
inline, not those declared inside of a header file. If you wish to define
an inline member function outside of the class definition (and use it in
other translation units), then you need to use the inline keyword. If you
have an inline member function that is only called in a single translation
unit containing its definition (e.g. a private member function), then you
could conceivably define it there, in an implementation (.cpp) file.
("Translation unit" essentially means "implementation file" + "included
headers in that implementation file")
c is of type char, sorry, should've posted that.
and operator[] is declared as:
char operator[](std::size_t index) const;

I need two versions, one non-const?

Yes. Have it return a reference, or some object that can act as a proxy for
the char.

char& operator[](std::size_t index);
 
E

E. Robert Tisdale

William said:
For some reason, I thought that any function defined in the header file
would be inlined automatically

And, depending upon the implementation, that may be just what happens.
and that I could use the keyword inline to request
functions defined in the implementation file (cpp-file) to be
inlined as well, provided they were short enough.

Some compilers do look for function definitions
in other translation units and inline them automatically.
That' one reason why inline function definitions
should be the same in *all* translation units.
So, if I want to request a
function to be inlined, it must be defined in the header?
Inside the class declaration itself?

If you define the function inside the class definition,
it is an inline function.
Or can it be outside (but still in the header)?

You must *declare* the function in the class definition
then use the 'inline' qualifier when you define the function
outside of the class definition.
Remember to define the inline function
*before* you invoke it or it will be inline'd
and your link editor may complain about "undefined references".
 
K

Kid

William Payne said:
Hello, I am toying with a simple string class I wrote quite some time ago. I
noticed that if I try to use operator == or != I get undefiend references,
but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

The code that triggers these undefined references is simply:
if(str == s2)
{
cout << "s2 == str" << endl;
}
else
{
cout << "s2 != str" << endl;
}

if(str != s2)
{
cout << "s2 != str" << endl;
}
else
{
cout << "s2 == str" << endl;
}

where str and s2 is of type String (my string class).

And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

what am I missing?

Thanks for any replies!

/ WP

IIRC, strcmp doesn't reside in namespace std; that is, remove the
std:: and you should be fine. Also, the correctness of foo[1] = c
depends on the type of c, though I'll take a leap of faith and assume
you meant foo[1] = 'c', in which case you'll need [] overlaoded to
begin with. You do realise there is a std::string already written,
right?
 
W

William Payne

Kid said:
William Payne said:
Hello, I am toying with a simple string class I wrote quite some time
ago. I
noticed that if I try to use operator == or != I get undefiend
references,
but I dont see why. In my class declaration I have:
bool operator==(const String& rhs) const;
bool operator!=(const String& rhs) const;
(In the public section.)

And in the implementation file of my little string class, I have:
inline bool
String::eek:perator==(const String& rhs) const
{
return std::strcmp(m_internal_string, rhs.m_internal_string);
}

inline bool
String::eek:perator!=(const String& rhs) const
{
return !((*this) == rhs);
}

The code that triggers these undefined references is simply:
if(str == s2)
{
cout << "s2 == str" << endl;
}
else
{
cout << "s2 != str" << endl;
}

if(str != s2)
{
cout << "s2 != str" << endl;
}
else
{
cout << "s2 == str" << endl;
}

where str and s2 is of type String (my string class).

And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!

what am I missing?

Thanks for any replies!

/ WP

IIRC, strcmp doesn't reside in namespace std; that is, remove the
std:: and you should be fine.

Then you should take a look at the standard C++ header <cstring>

/ WP
 
O

Old Wolf

William Payne said:
Hello, I am toying with a simple string class I wrote quite
some time ago.

And one more thing, if the compiler rejects:
String foo("bar");
foo[1] = c; // Doesn't like this line!
c is of type char, sorry, should've posted that.
and operator[] is declared as:
char operator[](std::size_t index) const;

If you return a char then how do you expect the original string to
be modified? Clearly you need to return a reference into the
actual storage of the string's contents.

Unfortunately you have to have 2 member functions for this:
char & operator[](int);
char const & operator[](int) const;
so that with const objects you get const references and with
non-const strings you get a non-const reference which you
can then modify. If you want to support volatile strings
then you also have to add:
char volatile & operator[](int) volatile;
char const volatile & operator[](int) const volatile;
It would be nice if there were some language feature
to prevent all this repetition.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top