I am going through the book C++ Primer, I am currently doing the programming exercises of chapter 11. I have troubles with exercise 4. My answer is exactly the same as the one here http://www.ignatkov.net/cppprimerplus/chapter11answers/c-primer-plus-chapter-11-exercise-4-answer
The compiler gives me an error for overloading the operator * with a friend function taking as arguments an object of the class time and a double.
The error message is:
Undefined symbols for architecture x86_64:
“operator*(Time const&, double)”, referenced from:
_main in “.o
operator*(double, Time const&) in “.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am using xcode 5.1.1
Does anyone knows what is going on and how I can fix it?
class Time
{
private:
int hours;
int minutes;
public:
Time();
Time(int h, int m = 0);
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
friend Time operator+(const Time & t1, const Time & t2);
friend Time operator-(const Time & t1, const Time & t2);
friend Time operator*(const Time & t, double n);
friend Time operator*(double m, const Time & t) { return t * m; } // inline definition
friend std::ostream & operator<<(std::ostream & os, const Time & t);
};
Time operator*(const Time & t, double mult)
{
Time result;
long totalminutes = t.hours * mult * 60 + t.minutes * mult;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
I don't think that is the problem. I removed the function in which I put the double as first argument and tested only the function in which a member of my class is the first argument, and I still get the same error.
Why are you defining as friend the operator functions such as operator+, operator- or operator*? You can define them as normal member functions! Usually, you define an operator function as friend, if the first parameter of that function is not of the same type of the class where you define it and you want that function to access to private member variables, like your operator<<, where the first parameter has to be a ostream object and the second is an object of the same type of your class!
EDIT: So you can declare your operators functions in this way:
1 2 3 4 5 6
const Time& operator+(const Time& t1);
//this function returns a constant reference to an object of type Time
const Time& operator-(const Time& t1);//here, as the previous one,
//I suppose you want to substract a certain object of type Time to the current one,
//so the only thing you need is to pass an object of type Time as parameter
const Time& operator*(double mult);
#include <iostream>
class Time
{
private:
int hours = 0;
int minutes = 0;
public:
//constructor with default parameters and initializer list to initialize internal status
Time(int h=0, int m = 0) :
hours( h>=0 ? h : 0), minutes( m>= 0 && m < 60? m : 0)//Initializer list
{ }
int getHours() const {return hours;}
int getMinutes() const { return minutes;}
void AddMin(int m);
void AddHr(int h);
void Reset(int h = 0, int m = 0);
const Time& operator*(int n)
{
hours = hours * n + minutes * n / 60;
minutes = minutes * n % 60;
return *this;//returns the current object "multiplied" by "n"
}
//You can define these 2 functions similar to the previous one!
const Time& operator+(const Time & t1);
const Time& operator-(const Time & t1);
friend std::ostream & operator<<(std::ostream & os, const Time & t)
{
os << t.hours <<" : "<<t.minutes;
return os;
}
};
int main()
{
Time t(3, 30);
std::cout << "hours: "<<t.getHours()<<"\n\n";
std::cout << "Minutes: "<<t.getMinutes()<<"\n\n";
t = t * 3;//here you are actually calling: t.operator*(3),
//and this function returns the current object muliplied by 3,
//which is then assigned to t again!!
std::cout << "hours: "<<t.getHours()<<"\n\n";
std::cout << "Minutes: "<<t.getMinutes()<<"\n\n";
std::cout << t<<std::endl;
std::cin.get();
return 0;
}
Hi Zwilu,
I am defining the operator functions as friends as this is what the exercise is calling for. I know how to define the operator functions as member functions, this is not a problem. My problem is that when I define the operator function * as a friend function with two arguments of a different type, I get the error message above. I believe my code is right, with either the first argument a member of the class or a double, but somehow I get an error with xcode. I was wondering why. From what I see from the error message it is a problem with linkage, something to do with architecture 32 or 64 bits maybe. I don't know exactly and I don't know how to fix it.
#include <iostream>
class Time
{
private:
int hours = 0;
int minutes = 0;
public:
//constructor with default parameters and initializer list to initialize internal status
Time(int h=0, int m = 0) :
hours( h>=0 ? h : 0), minutes( m>= 0 && m < 60? m : 0)//Initializer list
{ }
//other methods
friend std::ostream & operator<<(std::ostream & os, const Time & t)
{
os << t.hours <<" : "<<t.minutes;
return os;
}
friend Time& operator*(Time& t, int n)
//well you pass a non constant reference of type Time so that you can modify it
//you modify it and you return it!
{
t.hours = t.hours * n + t.minutes * n / 60;
t.minutes = t.minutes * n % 60;
return t;
}
};
int main(int argc, char** argv)
{
Time t(3, 40);
std::cout << "t before: "<<t << std::endl;
t = t * 3;//same as: t = operator*(t, 3);
//operator* is a friend function so you can't call it through one Time object:
//this should be wrong: t = t.operator*(t, 3);
std::cout << "t after: "<<t << std::endl;
return 0;
}
Thanks but I don't want to change the code, and I want to Time argument to be a constant, the code is not the problem, the problem is with the linker, or the libraries, I don't know.
I just found what the problem was, I put const Time & t as an argument in the prototype and just Time & t in the definition. Now that I put const in both the prototype and the definition it works fine.
Thank you for your help!
friendconst Time& operator*(const Time& t, int n)//passing a constant
{
Time t1(0, 0);//if you want to create another object, you can do it
t1.hours = t.hours * n + t.minutes * n / 60;
t1.minutes = t.minutes * n % 60;
return t1;
}
My little experiences says that, luckily, most of the errors are done by us and not by the linker or the compiler