trouble overloading operator * with a friend function for a class object and a double on xcode

Hi,

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?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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;
}
closed account (jvqpDjzh)
EDIT: from here you can read some general rules about operators overloading:
http://msdn.microsoft.com/en-us/library/4x88tzx0.aspx

Last edited on
Hi Zwilu,

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.
closed account (jvqpDjzh)
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);
Last edited on
closed account (jvqpDjzh)
What I have said in the first post was wrong. Sorry.
Last edited on
closed account (jvqpDjzh)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#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;
}


EDIT: Sorry, If I have made some mistakes :(
Last edited on
closed account (jvqpDjzh)
Your operator+ could be something similar to this:
1
2
3
4
5
6
7
8
9
10
11
12
13
    const Time& operator+(const Time & t1)
    {

        if((minutes += t1.minutes) > 59)//if minutes + t1.minutes > 59
        {
            hours += minutes/60 + t1.hours;// hours = hours + t1.hours + minutes/60
            minutes %= 60;// minutes =  minutes % 60//which the rest of minutes/60
//which is the number of hourse in the minutes.
        }
        else hours += t1.hours;
//if t1.minutes + minutes < 59, you don't have to increase hours!!! :)
        return *this;
    }

You could also control if the actual hours are >= 24 and manage also that situation!
I leave the rest as exercise to you!
Last edited on
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.
closed account (jvqpDjzh)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#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;
}
Last edited on
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!
Last edited on
closed account (jvqpDjzh)
1
2
3
4
5
6
7
    friend const 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

//in the main.cpp
1
2
3
4
	Time t(3, 40);
	std::cout << "t before: "<<t << std::endl;
	t = operator*(t, 3);
	std::cout << "t after: "<<t << std::endl;
Last edited on
You are right, even though in this case the error message was misleading.
Topic archived. No new replies allowed.