?
Solved

call by reference of operator function

Posted on 2003-03-24
16
Medium Priority
?
253 Views
Last Modified: 2010-04-01
In the case of operator overloading, Why call by reference is not accepted from the operator function argument ? suppose, i create three objects array and calling like object[0] = object[1] + object[2]
. whereas pointer is working. can you explain?

thanks
bhaskar roy
0
Comment
Question by:bhaskar_roy
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
  • 4
  • +2
16 Comments
 

Author Comment

by:bhaskar_roy
ID: 8193630
call by reference is not working whereas pointer is working.
0
 

Author Comment

by:bhaskar_roy
ID: 8193663
#include <iostream>
using namespace std;

class test
{
 int a;
 public:
 void assign();
 void display();
 test operator+(test &);
};

void test :: assign()
{
cout << "Enter A : " ;
cin >> a ;
}

void test :: display()
{
cout << "A : " << a << endl ;
}

test test :: operator+(test & t4)
{
 test tmp;
 tmp.a = a + t4.a; // here is the problem
 t4++;  // what is would be for next cell?
 tmp.a = tmp.a + t4.a; // here also
 return(tmp);
}

int main()
{
test t[4];
t[0].assign();
t[1].assign();
t[2].assign();
t[0].display();
t[1].display();
t[2].display();

cout << "After adding three objects of Same Class test\n" ;
t[2] = t[1] + t ; // t means t[0]
t[2].display();


return 0;
}
0
 
LVL 12

Expert Comment

by:Salte
ID: 8193824
The problem is that you try to do:

t4++; but you have no operator ++ (int) defined for test.

if you make the argument a pointer the t4++ will advance the pointer to next element - assuming that t4 points to an array of elements. If t4 does NOT point to an array you're pointing to some undefined place.

A reference type is semantically a pointer but syntactically a non-pointer, so:

T & x;

x++;

will invole the operator ++ (int) on an object of type T, so it will call:

x++ will be the same as x.operator ++(int);

T * p;

p++;

will NOT be the same as p -> operator ++(int) but will instead simply be incrementing the pointer.

If you give a by reference argument you don't want to increment the 'pointer' anyway since the pointer doesn't - in general - point to an element of an array.

A pointer on the other hand is a pointer and CAN in some cases be a pointer to an element in an array and in those cases will a ++p or p++ be meaningful.

If the reference happened to point to an element of an array you still cannot do ref++ or ++ref with the meaning of changing the reference. References cannot be assigned to, they can ONLY be initialized. Once initialized they are constant and cannot change.

T & ref;

ref = expr;

will not change ref but will change the object that ref references. Example:

int x = 3;
int & y = x;

y references x.

y = 5;

y is still referencing x, but x has changed value to 5.

The assignment doesn't change y but x!

Alf
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 30

Expert Comment

by:Mayank S
ID: 8193837
How did you call it by the pointer? Please show..

Mayank.
0
 

Author Comment

by:bhaskar_roy
ID: 8193925
#include <iostream>
using namespace std;

class test
{
 int a;
 public:
 void assign();
 void display();
 test operator+(test *);
};

void test :: assign()
{
cout << "Enter A : " ;
cin >> a ;
}

void test :: display()
{
cout << "A : " << a << endl ;
}

test test :: operator+(test * t4)
{
 test tmp;
 tmp.a = a + t4->a;
 t4++;
 tmp.a = tmp.a + t4->a;
 return(tmp);
}

int main()
{
test t[4];
t[0].assign();
t[1].assign();
t[2].assign();
t[0].display();
t[1].display();
t[2].display();

cout << "After adding three objects of Same Class test\n" ;
t[3] = t[2] + t ; // t means t[0]
t[3].display();


return 0;
}
0
 
LVL 1

Expert Comment

by:fsign21
ID: 8193932
the better way for operator+:
class test
{
int a;
friend operator+(const test& arg1, const test& arg2);
public:
...
};

test operator+(const test& arg1, const test& arg2) {
 test tmp;
 tmp.a = arg1.a + arg2.a;
 return(tmp);
}

It is better to define arg1 and arg2 as const because if you see
a = b+c;
you do not expect that b or c get changed by this operation.
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8193956
Ok, the code for doing it using the pointer seems to be all-right. But the t4 ++ statement in the overloading defined for the + operator will run for the pointer, but not when the argument is simply an object, because the ++ operator has not been overloaded for the object.

But why do you have two tmp.a = tmp.a + t4->a ; statements? Is it that you want to hold the sum of the first 3 elements in the 4th one??

Mayank.
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8193960
>> the better way for operator+:
>> test operator+(const test& arg1, const test& arg2)

Yeah! I would also agree with that.

Mayank.
0
 

Author Comment

by:bhaskar_roy
ID: 8194167
writing to mayank, only one argument. please check the programme, Is it correct ? write your comment.

#include <iostream>
using namespace std;

class test
{
 int a;
 public:
 void assign();
 void display();
 test operator+(test &);
};

void test :: assign()
{
cout << "Enter A : " ;
cin >> a ;
}

void test :: display()
{
cout << "A : " << a << endl ;
}

test test :: operator+(test & t4)
{
 test tmp;
 cout << "from operator : " << t4.a << endl ;
 tmp.a = a + t4.a ; // t4.a, is it syntactically right ?
 return(tmp);
}

int main()
{
test t[3];
t[0].assign();
t[1].assign();
t[2].assign();
t[0].display();
t[1].display();
t[2].display();

cout << "After adding three objects of Same Class test\n" ;
t[2] = t[1] + t ; // t means t[0]
t[2].display();


return 0;
}
0
 
LVL 12

Expert Comment

by:Salte
ID: 8194194
It is definitely the 'canonical way' to define the operator + for a type T:

T operator + (const T & a, const T & b);

This is how people expect the operator + to behave.

If you do:

T operator + (T & a, T & b);

You cannot do:

const T x;

T y = x + x;

The operator isn't defined for 'const' values and that is contrary to what users expect.

Further, having it as non-const implies that you plan to modify the argument and that simply isn't the way that + is supposed to be. People do not expect that:

c = a + b;

will modify a or b in any way, they expect c to be modified but neither one of a or b.

So, yes:

T operator + (const T & a, const T & b);

some times you have a type U which is naturally converted to T. Examples here is U is 'const char *' when T is a string type similar to std::string.

In this case you will have a one argument constructor taking a U as argument:

T::T(const U & u);

or

T::T(U u);

according to what is appropriate. It doesn't have to be exactly one argument but it can also have additional default arguments. You might also consider to make the constructor explicit:

class T {
public:
   explicit T(const U & u);
};

You also want to have an assignment operator taking a U:

T & T::opreator = (const U & u);

or

T & T::operator = (U u);

If you have an operator defined like:

T  opreator + (const T & a, const T & b);

You might also in some cases have additional operators defined like:

T operator + (const T & a, const U & b);
T operator + (const U & a, const T & b);

The following should be kept in mind. If you do not declare those additional operators it will still work and in many cases this lead to less code to write. In this case it might be just as well to omit them.

In some cases the case with U as argument instead of T becomes simpler to code in this case it might be an advantage to make explicit operator overloads for the type U so that that code will take advantage of the simpler case. In this case you write only those that are actually simpler than the one using T.

The point is that if you do not have an operator taking U as argument and you do:

T t;
U u;
T t2 = t + u;

The compiler will use the U overload if it is there, if there is none the compiler will convert the u value to a T type using the T(const U & u) constructor and will then call the operator taking T's as arguments.

For this reason you might want to define overloads for U if youwant to avoid that extra constructor call. If you do just as much work inside the function to compensate for the different type you might as well have that constructor call and remove that U overload.

If both T and U are classes you have the option of either providing a convertion from U to T by having a constructor in T that takes an argument of type U or you can make a conversion operator in U that convert to a T. You cannot have both as the compiler would then not know which one to call (constructor or conversion operator). If T is of predefined type or of a class not defined by you (provided by a library etc) you might want to provide the operator conversion instead:

class U {
public:
   operator T () { return T(....); }
};

Alf
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8194200
I don't think so. t4.a in the function is correct. But as far as the call in main () goes:

>> t[2] = t[1] + t ; // t means t[0] - ????

Actually, t would always mean &t[0], I mean the base-address of the array t[]. Because an array-name is always treated as a pointer to the first element. That's why while making the argument t4 as a pointer, it will execute fine, but in this case, it should not. So, you should write:

t[2] = t[1] + t[0] ;


Mayank.
0
 
LVL 12

Accepted Solution

by:
Salte earned 80 total points
ID: 8194295
Another thing,

if you use a one-argument version of the operator inside the class the canonical way is:

class X {
public:
   X operator + (const X & x);
};

There is ABSOLUTELY NO REASON to use plain reference unless you plan to modify the value.

The following rule is usually worth following:

1. If an object argument CAN be const it SHOULD be const.
In other words, only use non-const when you have to.

2. If a method CAN be static it SHOULD be static. (It cannot be both static and const so if it can be both it should be static).

3. If a method MUST be non-static but CAN be const it SHOULD be const.

4. Only specify a method as non-static and non-const if it modify non-static member data or call other methods that are non-static and non-const. In other words, only use non-static non-const when you have to.

The default for arguments should be const and you should only use non-const references when you must. This applies only to reference and pointer arguments. Value arguments doesn't modify the original value so it is not so strict in that case.

The default for methods should be STATIC if they do not refer to members of the object. One exception to this if they are virtual, however, in this case it is some times a good idea to define a static method that return the value when you want the value for a particular class and then have the virtual function call that static member function to return the value in a dynamic situation.

The default for non-static methods should be const unless they modify non-static non mutable members. Even if it does need to modify non-mutable members you should consider if perhaps that member should be made mutable or not. The question you should ask yourself in this case is: "How is this function or method supposed to act on a const object?". If the function should work well on a const object and still modify the member it should be mutable, if the function should fail on a const object (for example becuase it will modify the value of it) then the method should not be const. A mutable member should never reflect the 'value' of the object. For example a set object should not have the method that adds elements into the set defined as a const function. A function that finds the largest element of the set should be const though - it isn't supposed to modify the set and even if it does (for example sort it) it should do so by having the members declared mutable so that it can modify the object without having the value modified.

Only use non-const when you have asked yourself this question and made an opinion as to which members are mutable and not.

As a general rule whenever you write 'T & x' you should always ask yourself "did I really mean 'const T & x' ?" and if you did then you add that extra 'const' in front.

Alf
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8194311
>> please check the programme, Is it correct ? write your comment.

I don't think so. The 't4.a' in the function is correct. But as far as the call in main () goes:

>> t[2] = t[1] + t ; // t means t[0] - ????

Actually, t would always mean &t[0], I mean the base-address of the array t[]. Because an array-name is always treated as a pointer to the first element. That's why while making the argument t4 as a pointer, it will execute fine, but in this case, it should not. So, you should write:

t[2] = t[1] + t[0] ;


Mayank.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8195057
Actually, to be very precise an array isn't always treated as a pointer to first argument. However, the exceptions are very few:

sizeof(arr);

is one exception, another exception is this:

int arr[5];

Here it declares an array but it does not just declare a pointer to the first element of the array, the compiler makes room for the whole array at the place of the declaration.

A third exception is this:

void func(int arr[4]);


int array[4];

func(array);

Here it is really a hybrid in that the array is treated as a pointer to the first element, but as far as parameter matching goes it requires that the array has 4 elements.

Calling the array:

int array2[2];

func(array2);

should cause an error.

However, if you write:

void func2(int arr[])
{
   ....
}

It takes arrays of any size and the arr is the same as a pointer, in fact you can also give a pointer as argument for that array:

int * p;

func2(p);

should work fine.

Apart from these situations - at least as I can think of right now - an array is always treated as a pointer to the first element, so arr is the same as & arr[0].

Specifically if you just mention the array name in an expression it will always have an immediate conversion to pointer type unless that expression happen to be such that it takes an array of the given type as argument. (read sizeof()).

Alf
0
 
LVL 11

Expert Comment

by:bcladd
ID: 9558601
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Answered: Points to Salte

Please leave any comments here within the next seven days. Experts: Silence
means you don't care.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

-bcl (bcladd)
EE Cleanup Volunteer
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
Suggested Courses

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question