Confusion with * and &

This is a discussion on Confusion with * and & within the C++ Programming forums, part of the General Programming Boards category; Yeah I'm not familiar with this method either. It seems like its acting like it prints that function with the ...

  1. #16
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Yeah I'm not familiar with this method either. It seems like its acting like it prints that function with the cout whenever an "Apple& **operator here**" is CHANGED?

    Code:
    Apple& operator=(const Apple& anApple)
    	{
    		cout<<"assignment operator called"<<endl;
    		
    		num = anApple.num;
    		return *this;
    	}
    It seems (const Apple& anApple) is the function arguement area, and operator= is not a function name but a keyword saying if an operator of Apple& is changed then it calls that. And of course its using references and reference to reference to keep the correct value.

    I dunno, and whats with return *this;? I've read it in win32 tutorials but I never knew what "this" really meant.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  2. #17
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    "this" is the current class, I think. So returning *this would return a pointer to the current object.

  3. #18
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    Quote Originally Posted by dwks
    Code:
    Apple& operator=(const Apple& anApple) {
        cout<<"assignment operator called"<<endl;
    		
        num = anApple.num;
        return *this;
    }
    This overloads the = operator. So every time = is used on class Apple, this function is called.
    Ah, I see, so the parameter is the value that you assign it to, and the return is what it's assigned? For example:
    Code:
    Apple& anApple = someApple;
    someApple would be the parameter, and anApple would be assigned what is returned in the function?
    Also, it has Apple& operator, so that works only when assigned a reference to an Apple? and can you overload other operators, such as +, and if so would it be the same syntax but, + instead of =? Like Apple& operator+(...) {}

    Also, it says return *this. Is this referring to the current Apple object?

  4. #19
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    It seems like its acting like it prints that function with the cout whenever an "Apple& **operator here**" is CHANGED?
    Whenever you use =.

    Code:
    Apple a, b;
    a = b;  // operator= called here

  5. #20
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Also, it says return *this. Is this referring to the current Apple object?
    . . . and anApple would be assigned what is returned in the function?
    Yes on both counts.

  6. #21
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by dwks
    Whenever you use =.

    Code:
    Apple a, b;
    a = b;  // operator= called here
    Ah I see, duh, "assignment (=) operator called" >.< -Thanks.

    Cool explaning Ganoosh, and confirmation dwks, thanks that helped me learn something very new
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  7. #22
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    Big gold star for 7stud.
    Woohoo! My first one.

    Can you explain what's going on there? It looks like a reference is being assigned to a function?
    It does what's called "operator overloading". For a class, you can define what almost any operator does to your class objects--operators being things like:

    +
    =
    <
    [ ]
    *

    For instance, if the Apple class looks like this:
    Code:
    class Apple
    {
    public:
    	int size;
    	string color;
    };
    and you want to be able to write:

    myApple = yourApple

    You can decide what should happen: you can define '=' to just assign the int value of yourApple to myApple, or you can assign the string value as well, or you can do something crazy and multiply the ints together and add the strings together(although that isn't recommended). The syntax for operator overloading can be tricky, and it varies depending on what the operator is, so you have to learn about it.

    The reason I put the operator= function in the Apple class is because there are several default functions that the compiler provides for a class, so it's not always clear what is happening. In other words, sometimes invisible default functions are being called that you don't know about. In this case, the default operator= was being called when I wrote this statement:

    ref = yourApple;

    By explicitly defining the operator= function, and having it print out a message, the class explicitly displays what was previously taking place invisibly behind the scenes.

    Ah, I see, so the parameter is the value that you assign it to, and the return is what it's assigned? For example:
    Code:
    Apple& anApple = someApple;
    Typically, with operator overloading the parameter is what's on the right hand side of the operator(the equals sign in this case), and often the parameter will be named 'rhs' for "right hand side".

    someApple would be the parameter, and anApple would be assigned what is returned in the function?
    someApple would be the parameter and the return type of the function is an Apple reference:

    Apple&

    Remember, putting a reference in front of a parameter name or a return type does not affect the type of what you send to the function or return from the function. With that return type, the function should return an Apple object. For function parameters, you can think of it this way: a parameter name creates a local function variable. So, if you have a parameter:

    Apple& anApple

    what type of variable do you send the function? Well, think about how you create a reference in main();

    Apple myApple;
    Apple& ref = myApple;

    In main(), when you create an Apple reference, the reference is expecting that you will assign it an Apple object. The same thing takes place with a function parameter: if the parameter is an Apple reference, then it expects you will send it an Apple object because the argument is assigned to the parameter variable--just like in the previous code example.

    Also, it says return *this. Is this referring to the current Apple object?
    'this' is a pointer to the object that is calling the function, which is the object on the left hand side of the equals sign. Since the return type is an Apple reference, you need to return an Apple object. If you dereference 'this', then you have an Apple object. You might ask why you need to return anything: the left hand side object is calling a method, which changes its member variables, so why return anything. You don't have to return anything, but the reason you do is so you can write chained statements like this:

    myApple = yourApple = anotherApple;

    That statement is excuted in this order:

    myApple = (yourApple = anotherApple);

    If you don't return anything from your operator= function, you will be left with this:

    my Apple = (nothing);

    And the const Apple& anApple, does the variable passed into a function or otherwise that takes a const need to be const itself?
    Nope.

    Or does it make the copy a const within the function?
    When a function parameter has const in front of it, it means the function cannot use the pointer or reference to change the object. Here is an example:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* ptr)
    {
    	ptr->num = 200; 
    }
    
    int main()
    {
    	
    	Apple myApple;
    	myApple.num = 10;
    	Apple* myPtr = &myApple;
    
    	changeIt(myPtr);
    	cout<<myApple.num<<endl; //200
    
    	return 0;
    }
    If you put const in front of the function parameter:
    Code:
    void changeIt(const Apple* ptr)
    {
    	...
    }
    the program won't compile. Therefore, if you don't want your function to inadvertently change an object whose pointer or reference you pass to the function, you can put const in front of the parameter name. You should do that as much as possible, and then the compiler will alert you to any inadvertent mistakes you make inside the function.
    Last edited by 7stud; 06-21-2005 at 10:45 PM.

  8. #23
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    Oooh, much more clear now. So a const object isn't an unchangeable object, but disalllows through a pointer or reference, as a safehold. Also, with operator overloading, you can have different return types? Or does the return type have to be of that class because it's being used only with that class? And you can return a reference, pointer, or just plain object, so does that mean you can define a different = operator for each a pointer and an object, or do all rely on one overload?
    The syntax for operator overloading can be tricky, and it varies depending on what the operator is, so you have to learn about it.
    So assigning + would not be like:
    Code:
    Apple& operator+(const Apple& anApple)
    	{
    		cout<<"addition operator called"<<endl;
    		
    		num += anApple.num;
    		return *this;
    	}
    or would it for some and for not? I mean, like the example you posted with the assignment operator (=), you can't just copy that and change the = to a +, *, etc and change the function body and parameters, etc to your class and what it should do, but it is different syntax?

  9. #24
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    So a const object isn't an unchangeable object, but disalllows through a pointer or reference, as a safehold.
    A const object is unchangeable. But, you don't have to send a const object to a function that has a const object as a parameter. The function will treat the object as const, so in essence the object temporarily becomes const.

    Also, with operator overloading, you can have different return types? Or does the return type have to be of that class because it's being used only with that class?
    Sorry, I added something to my previous post that addresses why you even need a return type at all. You can define a function to return anything you want. For instance, you could return an int from an operator= function if that is what you want to do.

    And you can return a reference, pointer, or just plain object, so does that mean you can define a different = operator for each a pointer and an object, or do all rely on one overload?
    The compiler can't distinguish between functions that only differ by return type. Here is an example:
    Code:
    #include <iostream>
    using namespace std;
    
    
    void func(int num)
    {
         //do something
    }
    
    int func(int num)
    {
    	return 10;
    }
    
    
    int main()
    {
    	
    	int num = func(5); //error--overloaded functions differ only by return type
    
    	return 0;
    }
    ------------

    So assigning + would not be like:
    Code:
    Apple& operator+(const Apple& anApple)
    	{
    		cout<<"addition operator called"<<endl;
    		
    		num += anApple.num;
    		return *this;
    	}
    or would it for some and for not? I mean, like the example you posted with the assignment operator (=), you can't just copy that and change the = to a +, *, etc and change the function body and parameters, etc to your class and what it should do, but it is different syntax?
    Overloading operator+ is slightly different. When calling the operator= method, all the left hand side object does is call a method that changes its member variables. With operator+, you need to create a new object that is the sum of two objects. You wouldn't write something like this:

    Apple newApple = myApple + yourApple;

    and expect that myApple or yourApple would be altered to hold the sum of the two objects. So, the operator+ has to create a new object and return it, so that you end up with this:

    Apple newApple = <new object>;

    with both myApple and yourApple remaining unaltered. (Looking ahead you might also notice that the operator= is going to be called after the operator+ does its thing.) So, inside operator+, you need to call a constructor for the Apple class to create an Apple object. Assuming there was an appropriate constructor defined for Apple, you would do something like this:

    Apple sumApples(num + anApple.num);

    and then return that Apple object.

    However, you can't list the return type as an Apple reference. The Apple object you create inside the function is a local object, which means it will be destroyed when the function ends. Since a reference is implemented as a pointer behind the scenes, it will point to an object that has been destroyed, so the reference will be invalid, and your program will crash.

    The solution to that problem is our old friend "pass by value". If the return type is listed as Apple instead of Apple&, what will happen? Well, just like you can "pass by value" when you send an argument to a function, you can "pass by value" when you return something from a function. When the return type is listed as Apple, and you return the new Apple object you created in a return statement, a copy of the Apple object will be created in memory and the copy is what's returned. Just like before, when the functions ends, the local Apple object you created inside the function will get destroyed, but back in main() the program will have the copy to use, and because you didn't return a reference there won't be a reference pointing to invalid memory.

    Finally, there is one more thing that is different for operator+. With operator+, you can declare the function as const:

    Apple operator+(Apple& rhs) const;

    Since the left hand side object isn't being changed by the method it calls, the function should be declared const. Constant methods can be called by const objects because they guarantee that the method won't change the object. Const methods can also be called by regular objects. Regular objects don't care whether they are changed or not, so the extra security of a const method doesn't matter one way or the other to them. If you don't declare the method as const, then const objects can't call the method, so when you can, you should declare a method as const. Note: const doesn't apply to functions that aren't members of a class since they aren't called by objects.

    Here is how operator+ would look like:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    	
    	Apple() {};
    	
    	Apple(int n)
    	{
    		num = n;
    	}
    
    	Apple& operator=(const Apple& anApple)
    	{
    		cout<<"assignment operator called"<<endl;
    		
    		num = anApple.num;
    		return *this;
    	}
    
    	Apple operator+(const Apple& anApple) const
    	{
    		return Apple(num + anApple.num);
    	}
    };
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    
    	//new code:
    
    	Apple newApple = myApple + yourApple;
    	cout<<endl<<newApple.num<<endl;
    
    
    	return 0;
    }
    Now, here's a question for you: run that program and examine the output. Why wasn't the operator= function called a second time?
    Last edited by 7stud; 06-21-2005 at 10:56 PM.

  10. #25
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by 7stud
    Now, here's a question for you: run that program and examine the output. Why wasn't the operator= function called a second time?
    Because newApple isnt a reference object to the Apple class (its an object to the Apple class), and also newApple is being initialized there wheras the operation function (up there in the code) is only called on assignment.

    Thanks for all that explanation, gonna have to bookmark it for rereading o.o
    Last edited by Dae; 06-22-2005 at 12:42 AM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  11. #26
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    10
    assignment operator called
    30

    60

    That's the output I got. I'm guessing it wasn't called because the addition operator returned a new Apple and newApple got assigned to the new Apple, to point to, rather than call the assignment operator of the class and set it's values to that of the the new Apple. I'm noticing it's outputting 60 as the result though. Is this becaues it's not calling operator=? And you said you can return any type, such as an int. But doesn't it know to call the operator in the class by the lhs? By assigning an something to an Apple? I made a sample program:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple {
    public:
           int num;
           int operator=(const Apple& anApple) {
               cout<<"Apple to int assignment called"<<endl;
               return anApple.num;
           }
           
           Apple& operator=(const int num) {
               cout<<"int to Apple assignment called"<<endl;
               this->num = num;
               return *this;
           }
    };
    
    int main() {
        Apple myApple;
        myApple.num = 5;
        
        /*int* appleNum = myApple;
        cout<<appleNum<<endl; // 5*/
        
        myApple = 30;
        cout<<myApple.num<<endl; // 30
        cin.get();
    }
    I noticed you can pass any parameter, I made one that would set an Apple to an int, it worked. However the part that assigns and int is commented out because when I tried to compile it said cannot convert type Apple to int. Is this because you can't do it, or is my function wrong?

  12. #27
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Nevermind! Read my post after this.

    I noticed it still gives you the error that you cant assign Apple to int if you dont declare a return, which 7plug said would mean it would equal nothing, so itd be appleNum = ;, but its still giving the error.. leaving me to believe converting this way would require more work. I mean converting int to Apple probably works because you get to work with the 'this', which you cant do with the int to Apple because the 'this' is the object you are currently in for that class, but for int to Apple you arent in any object, you are in an int.

    So what you are essentially doing for your int to Apple code would be like having this Apple to int code, which doesnt work eh:
    Code:
               Apple& operator=(const int num) {
               cout<<"int to Apple assignment called"<<endl;
               
               return num;
              }
    And yah thats wierd its outputting 60 in his example, its because 'num' is whatever num of the current object is, which is the lhs object (newApple), or at least I thought.. while testing I found out that even though newApple is a new object when testing with a cout its saying num is already 30, and testing with the yourApple object will change that number, and you can move yourApple around in the definition: Apple newApple = myApple + yourApple; and it still uses yourApple, and defining the yourApple object before myApple instead of visa versa still doesnt change anything. Also removing the operator= doesnt change the output. Its very odd, but explains why its outputting 60.. its basicly just adding anApple together twice.

    Just read this modded version and you'll see:

    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    	
    	Apple() {};
    	
    	Apple(int n)
    	{
            cout << endl << "num in constructor: " << num; // it doesnt seem to be 30 here though
    		num = n;
    	}
    
    	Apple& operator=(const Apple& anApple)
    	{
    		cout<<"assignment operator called"<<endl;
    		
    		num = anApple.num;
    		return *this;
    	}
    
    	Apple operator+(const Apple& anApple) const
    	{
            cout << "anApple.num (input): " << anApple.num;
            cout << endl << "num in function: " << num; // why the hell is this set to 30 already?
    		return Apple(num+anApple.num);
    	}
    };
    
    int main()
    {
        
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    
    	//new code:
    
    	Apple newApple = myApple + yourApple;
    	cout << endl << "final outcome: " << newApple.num << endl;
    
        cin.get();
    
    	return 0;
    }
    Anyone explanation?
    Last edited by Dae; 06-22-2005 at 01:38 AM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  13. #28
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    The reason the result is 60, is because I, and you apparently, neglected to acknowledge that damned ref that was sitting in the code from before as an example:

    Code:
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    It's making myApple = yourApple, and yourApple is 30.. you're adding 30 to 30.. hence 60. Case Closed.

    I'm gonna slap 7stud, that was fun!

    I need more of those.. kinda like debugging code for experience, gotta learn some way.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  14. #29
    Registered User
    Join Date
    Apr 2003
    Posts
    2,662
    I'm noticing it's outputting 60 as the result though. Is this because it's not calling operator=?
    As was previously discussed, this line:

    ref = yourApple;

    copies yourApple into ref. But, ref can be thought of as a synonym(=an alternate name) for myApple because of this line:

    Apple& ref = myApple;

    so the line:

    ref = yourApple;

    changed myApple's member variable to 30, and when you add myApple and yourApple you get 60. Sorry, I should have gotten rid of the reference stuff in main() left over from the previous example.

    Here is a clearer example of the operator+ in action:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    
    	
    	Apple(){}
    
    	Apple(int n)
    	{
    		num = n;
    	}
    
    	Apple operator+(const Apple& rhs) const
    	{
    		return Apple(num + rhs.num); 
    	}
    
    	Apple& operator=(const Apple& rhs)
    	{
    		if(this == &rhs) //checks to see if lhs and rhs are the same objects
    		{
    			cout<<"they're equal, exiting function directly"<<endl;
    			return *this; //if lhs==rhs, then executing the code below is unnecessary
    		}
    
    		cout<<"assignment operator called"<<endl;
    		num = rhs.num;
    		return *this;
    	}
    
    };
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple newApple = myApple + yourApple;
    	cout<<endl<<newApple.num<<endl;
    	
    	//tests new portion of operator=
    	Apple& ref1 = myApple;
    	Apple& ref2 = myApple;
    
    	ref1 = ref2;
    	
    	return 0;
    }
    Note: I added a new portion to the operator= function. You should make that check, so that you don't execute a bunch of code unnecessarily.

    I'm guessing [the operator=] wasn't called because...
    Sorry, I can't explain it either. I thought I would be able to. I presumed another of the default functions the compiler supplies, namely the default copy constructor, was invisibly executing behind the scenes instead of the operator= function, but when I explicitly defined a copy constructor for the Apple class, it wasn't called either. I put display messages in the default constructor and the int constructor as well, and none of them displayed a message. So, it appears newApple is being created without a call to a constructor, which is impossible. One of the pros will have to weigh in on that, but I doubt any of them will wade through all these posts and end up here. I'll think about it some more, and if I figure it out, I'll post what's happening--otherwise I'll ask the pros by starting another thread.

    And you said you can return any type, such as an int. But doesn't it know to call the operator in the class by the lhs? By assigning an something to an Apple?
    Sorry, I can't make out what you are saying there. But, if you define your operator= function like this:
    Code:
    int operator=(const Apple& anApple) 
    {
           cout<<"Apple to int assignment called"<<endl;
               return anApple.num;
    }
    then you have to use it like this:
    Code:
    Apple myApple;
    myApple.num = 5;
    
    Apple yourApple;
    yourApple.num = 25;
        
    int appleNum = myApple = yourApple;
    That last line is equivalent to:

    int appleNum = (myApple = yourApple);

    and the way it's executed goes like this: myApple calls the operator= method that takes an Apple object as a parameter. That method returns an int. So, you replace the part that's enclosed in parentheses with the int to produce:

    int appleNum = (25);

    Your attempt looks like this:

    int* appleNum = myApple;

    Remember, the left hand side is the object that is calling the operator= method. Is appleNum an object of the Apple class? The answer is no, so appleNum can't call any method in the Apple class. So, the compiler looks around outside the Apple class for an operator= method defined for the int* class that takes an Apple object as a parameter(that's what's on the rhs of the equals sign), and can't find anything, so you get an error.
    Last edited by 7stud; 06-22-2005 at 02:46 AM.

  15. #30
    Dae
    Dae is offline
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Quote Originally Posted by 7stud
    Sorry, I can't explain it either. I thought I would be able to. I presumed another of the default functions the compiler supplies, namely the default copy constructor, was invisibly executing behind the scenes instead of the operator= function, but when I explicitly defined a copy constructor for the Apple class, it wasn't called either. I put display messages in the default constructor and the int constructor as well, and none of them displayed a message. So, it appears newApple is being created without a call to a constructor, which is impossible. One of the pros will have to weigh in on that, but I doubt any of them will wade through all these posts and end up here. I'll think about it some more, and if I figure it out, I'll post what's happening--otherwise I'll ask the pros by starting another thread.
    You must have missed my posts, but I said:

    The operator= wasnt being called because as your very own 'cout' says.. it is called on assignment. The line of code you have there is initialization:

    initiailzation:
    Apple newApple = myApple + yourApple; // doing it in one step wont call it :-/

    assignment:
    Apple newApple; // initialization
    newApple = myApple + yourApple; // assignement
    Last edited by Dae; 06-22-2005 at 05:43 AM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

Page 2 of 3 FirstFirst 123 LastLast
Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21