Operatr+ Updated

N

Nephi Immortal

I read the topic – "Error operator+ function” in the previous
thread. Other folks explained how to put three possible operator+
functions.
I wrote two versions of class A and class B. Both classes are
similar, but one data member of class B uses reference instead of
value.
I cannot use class A version. I am told not to use copy constructor
function. If I do, then copy constructor will have undefined
behavior. I should always place it in private.
They said not to put const on any function’s parameter if parameter
is built-in type such as int. Please clarify why I should not use
const? Const is necessary to prevent changing parameter and I always
create temporary local variable and copy const parameter to it.
Take a look at class A and class B. Compare both of them. Class B
is ideal to be helper class or proxy class.

You can write like

_Low_Byte Low_Byte()
and
_High_Byte High_Byte()

Both functions are in class A.

You can create two classes: _Low_Byte and _High_Byte. The class B is
inherited into _Low_Byte class and _High_Byte class. You need to
redefine operator=.

I do not need to post two classes since you understood what my code
means.

I believe that class A is to be correct code design. What about
class B?

class A {
public:
explicit A( unsigned int data );
~A();
A( const A &right );
A &operator=( const A &right );

A &operator=( unsigned int data );
operator unsigned int();

friend A operator+( const A &left, const A &right );
friend A operator+( const A &left, unsigned int right );
friend A operator+( unsigned int left, const A &right );

friend A operator+=( const A &left, const A &right );
friend A operator+=( const A &left, unsigned int right );
friend A operator+=( unsigned int left, const A &right );


private:
unsigned int m_data;
};

A::A( unsigned int data ) : m_data( data ) {
}

A::~A() {
}

A::A( const A &right ) : m_data( right.m_data ) {
}

A &A::eek:perator=( const A &right ) {
m_data = right.m_data;
return *this;
}

A &A::eek:perator=( unsigned int data ) {
m_data = data;
return *this;
}

A::eek:perator unsigned int() {
return m_data;
}

A operator+( const A &left, const A &right ) {
return A( left ) += right;
}

A operator+( const A &left, unsigned int right ) {
return A( left ) += right;
}

A operator+( unsigned int left, const A &right ) {
return left += A( right );
}

A operator+=( const A &left, const A &right ) {
A t( left );
t.m_data += right.m_data;
return t;
}

A operator+=( const A &left, unsigned int right ) {
A t( left );
t.m_data += right;
return t;
}

A operator+=( unsigned int left, const A &right ) {
A t( right );
t.m_data += left;
return t;
}

class B {
public:
explicit B( unsigned int &data );
~B();
B( const B &right );
B &operator=( const B &right );

B &operator=( unsigned int data );
operator unsigned int();

friend unsigned int operator+( const B &left, const B &right );
friend unsigned int operator+( const B &left, unsigned int right );
friend unsigned int operator+( unsigned int left, const B &right );

friend unsigned int operator+=( const B &left, const B &right );
friend unsigned int operator+=( const B &left, unsigned int right );
friend unsigned int operator+=( unsigned int left, const B &right );


private:
unsigned int &m_data;
};

B::B( unsigned int &data ) : m_data( data ) {
}

B::~B() {
}

B::B( const B &right ) : m_data( right.m_data ) {
}

B &B::eek:perator=( const B &right ) {
m_data &= 0xFF00u;
m_data |= ( right.m_data & 0xFFu );
return *this;
}

B &B::eek:perator=( unsigned int data ) {
m_data &= 0xFF00u;
m_data |= ( data & 0xFFu );
return *this;
}

B::eek:perator unsigned int() {
return m_data & 0xFFu;
}

unsigned int operator+( const B &left, const B &right ) {
unsigned int t = left.m_data;
t += right.m_data;
return t;
}

unsigned int operator+( const B &left, unsigned int right ) {
unsigned int t = left.m_data;
t += right;
return t;
}

unsigned int operator+( unsigned int left, const B &right ) {
unsigned int t = right.m_data;
t += left;
return t;
}

unsigned int operator+=( const B &left, const B &right ) {
unsigned int t = left.m_data;
t += right.m_data;
return t;
}

unsigned int operator+=( const B &left, unsigned int right ) {
unsigned int t = left.m_data;
t += right;
return t;
}

unsigned int operator+=( unsigned int left, const B &right ) {
unsigned int t = right.m_data;
t += left;
return t;
}


int main () {
A a( 2 ), b( 4 ), c( 0 );

c = a + b;
c = a + 5u;
c = 7u + b;

unsigned int data = 0x1234u, data2 = 0x5678u, data3 = 0xCCCCu;
B d( data ), e( data2 ), f( data3 );

f = d + e;
f = d + 0x10u;
f = 0x30u + e;

return 0;
}
 
I

Ian Collins

I read the topic – "Error operator+ function” in the previous
thread. Other folks explained how to put three possible operator+
functions.
I wrote two versions of class A and class B. Both classes are
similar, but one data member of class B uses reference instead of
value.
I cannot use class A version. I am told not to use copy constructor
function. If I do, then copy constructor will have undefined
behavior. I should always place it in private.

Told by whom and in what context?
They said not to put const on any function’s parameter if parameter
is built-in type such as int.Please clarify why I should not use
> const?

That's because it doesn't have any meaning for a value parameter (the
same would apply for any type passed by value).
Const is necessary to prevent changing parameter and I always
create temporary local variable and copy const parameter to it.

That only applies if the parameter is a reference or a pointer. Both of
these refer to objects in the scope of the caller, so declaring the
parameter const prevents the called function changing the original
value. Value parameters are copies of the original, Changing them has
no effect on the the original.
Take a look at class A and class B. Compare both of them. Class B
is ideal to be helper class or proxy class.

You can write like

_Low_Byte Low_Byte()
and
_High_Byte High_Byte()

Both functions are in class A.

You can create two classes: _Low_Byte and _High_Byte. The class B is
inherited into _Low_Byte class and _High_Byte class. You need to
redefine operator=.

This is hard to parse.
I do not need to post two classes since you understood what my code
means.

I believe that class A is to be correct code design. What about
class B?

class A {
public:
explicit A( unsigned int data );
~A();
A( const A&right );
A&operator=( const A&right );

A&operator=( unsigned int data );
operator unsigned int();

friend A operator+( const A&left, const A&right );
friend A operator+( const A&left, unsigned int right );
friend A operator+( unsigned int left, const A&right );
>
friend A operator+=( const A&left, const A&right );
friend A operator+=( const A&left, unsigned int right );
friend A operator+=( unsigned int left, const A&right );

These should be members, returning A&. += updates the current instance,
it doesn't create a new one.
private:
unsigned int m_data;
};

class B {
public:
explicit B( unsigned int&data );

Why do you use an int& here?

I won't comment further, I'm not sure what B is doing.
 
N

Nephi Immortal

Told by whom and in what context?


 > const?

That's because it doesn't have any meaning for a value parameter (the
same would apply for any type passed by value).


That only applies if the parameter is a reference or a pointer.  Both of
these refer to objects in the scope of the caller, so declaring the
parameter const prevents the called function changing the original
value.  Value parameters are copies of the original, Changing them has
no effect on the the original.






This is hard to parse.











These should be members, returning A&.  += updates the current instance,
it doesn't create a new one.






Why do you use an int& here?

I won't comment further, I'm not sure what B is doing.

I tried to explain above. Class B needs to use reference on
constructor and data member. I did not post two functions. It should
clarify clearly.

Class A {
....
B Low_Byte();
B High_Byte();
....
};

B Low_Byte() {
Return B( this->m_data );
}

B High_Byte() {
Return B( this->m_data );
}

Now, you see class B modifies class A’s data member through reference
when Low_Byte() function is called. It looks like this.

A a( 2 ), b( 4 ), c( 0 );
c.Low_Byte() = a.Low_Byte() + b.Low_Byte();

You notice that class B’s operator+ only returns unsigned int instead
of returning class B reference. Returning class B reference can cause
to modify class A’s data member incorrectly through class B’s copy
constructor since returning class B should be local and not
reference. Returning unsigned int is the answer and class B’s
operator=( unsigned int ) is called before reference can modify class
A’s data member correctly.

Am I saying clearly?

Please explain why you think operator+ should be member function. It
needs to be global function because it has three possible operator+.
Other folks explained this earlier.
 
I

Ian Collins

I tried to explain above. Class B needs to use reference on
constructor and data member. I did not post two functions. It should
clarify clearly.

Class A {
....
B Low_Byte();
B High_Byte();
....
};

B Low_Byte() {
Return B( this->m_data );
}

B High_Byte() {
Return B( this->m_data );
}

Now, you see class B modifies class A’s data member through reference
when Low_Byte() function is called. It looks like this.

A a( 2 ), b( 4 ), c( 0 );
c.Low_Byte() = a.Low_Byte() + b.Low_Byte();

You notice that class B’s operator+ only returns unsigned int instead
of returning class B reference. Returning class B reference can cause
to modify class A’s data member incorrectly through class B’s copy
constructor since returning class B should be local and not
reference. Returning unsigned int is the answer and class B’s
operator=( unsigned int ) is called before reference can modify class
A’s data member correctly.

Am I saying clearly?

Yes, that makes more sense.
Please explain why you think operator+ should be member function. It
needs to be global function because it has three possible operator+.
Other folks explained this earlier.

I didn't say that, I said operator += should be a member. Please
comment in-line, it makes replying with relevant context easier.
 
J

James Kanze

I read the topic – "Error operator+ function” in the previous
thread. Other folks explained how to put three possible operator+
functions.
I wrote two versions of class A and class B. Both classes are
similar, but one data member of class B uses reference instead of
value.
I cannot use class A version. I am told not to use copy constructor
function. If I do, then copy constructor will have undefined
behavior. I should always place it in private.
They said not to put const on any function’s parameter if parameter
is built-in type such as int. Please clarify why I should not use
const? Const is necessary to prevent changing parameter and I always
create temporary local variable and copy const parameter to it.
Take a look at class A and class B. Compare both of them. Class B
is ideal to be helper class or proxy class.
You can write like
_Low_Byte Low_Byte()
and
_High_Byte High_Byte()
Both functions are in class A.
You can create two classes: _Low_Byte and _High_Byte. The class B is
inherited into _Low_Byte class and _High_Byte class. You need to
redefine operator=.
I do not need to post two classes since you understood what my code
means.
I believe that class A is to be correct code design. What about
class B?
class A {
public:
explicit A( unsigned int data );
~A();
A( const A &right );
A &operator=( const A &right );
A &operator=( unsigned int data );
operator unsigned int();

This looks like an excellent decision: making the conversion
constructor explicit, then overriding operator=. On the other
hand, I'm just slightly sceptical about one thing: most of the
time when you implement a class, you want it's operators, and
not those of the built-in type, whenever the class is used. The
presence of a user defined conversion operator means that you
risk getting just the opposite. User defined conversion
operators tend to be very dangerous. (I believe C++0x allows
them to be declared explicit. This would alleviate most of the
danger.)
friend A operator+( const A &left, const A &right );
friend A operator+( const A &left, unsigned int right );
friend A operator+( unsigned int left, const A &right );

Just a nit, but if the operators aren't defined inline, why make
them friend?
friend A operator+=( const A &left, const A &right );
friend A operator+=( const A &left, unsigned int right );
friend A operator+=( unsigned int left, const A &right );

The usual convention is for the first to to be members, not
friends (although IMHO, there is a good argument for making them
non-members, but with a non-const left parameter). As for the
last, it's probably irrelevant, since the it is covered by the
builtin operator += and the conversion operator.

At any rate, += should modify it's left arguement, so passing it
a reference to const is out.
private:
unsigned int m_data;
};
A::A( unsigned int data ) : m_data( data ) {
}
A::~A() {
}
A::A( const A &right ) : m_data( right.m_data ) {
}
A &A::eek:perator=( const A &right ) {
m_data = right.m_data;
return *this;
}

Given the definition of the last three, I'd just let the
compiler take care of them (with perhaps a comment saying that
the compiler provided defaults are used).
A &A::eek:perator=( unsigned int data ) {
m_data = data;
return *this;
}
A::eek:perator unsigned int() {
return m_data;
}
A operator+( const A &left, const A &right ) {
return A( left ) += right;
}
A operator+( const A &left, unsigned int right ) {
return A( left ) += right;
}
A operator+( unsigned int left, const A &right ) {
return left += A( right );
}

Given these definitions, why friend?
A operator+=( const A &left, const A &right ) {
A t( left );
t.m_data += right.m_data;
return t;
}

This is very dubious. A += operator which doesn't modify the
left argument? I'd call this operator overloading abuse, and
very, very poor design.
A operator+=( const A &left, unsigned int right ) {
A t( left );
t.m_data += right;
return t;
}
A operator+=( unsigned int left, const A &right ) {
A t( right );
t.m_data += left;
return t;
}
class B {
public:
explicit B( unsigned int &data );
~B();
B( const B &right );
B &operator=( const B &right );
B &operator=( unsigned int data );
operator unsigned int();
friend unsigned int operator+( const B &left, const B &right );
friend unsigned int operator+( const B &left, unsigned int right );
friend unsigned int operator+( unsigned int left, const B &right );
friend unsigned int operator+=( const B &left, const B &right );
friend unsigned int operator+=( const B &left, unsigned int right );
friend unsigned int operator+=( unsigned int left, const B &right );
private:
unsigned int &m_data;

It's almost always an error to have a reference as a data
member. And I can't think of a single exception when the class
has value semantics, as is the case here. Value semantics imply
both copy and assignment, and that both have roughly the same
semantics. Which isn't possible with reference members.
B::B( unsigned int &data ) : m_data( data ) {
}

B::~B() {
}

B::B( const B &right ) : m_data( right.m_data ) {
}
B &B::eek:perator=( const B &right ) {
m_data &= 0xFF00u;
m_data |= ( right.m_data & 0xFFu );
return *this;
}

Note that this could have very undesirable semantics because of
the reference member. You could end up modifying the value of
right.
 
J

James Kanze

On 02/20/11 09:04 AM, Nephi Immortal wrote:
These should be members, returning A&. += updates the current instance,
it doesn't create a new one.

That they should be members is the conventional approach. One
could argue that they should be non-members, taking an A& (no
const) as argument: the built-in += requires an lvalue as left
argument; the only way to simulate this is to have a non-member
taking a reference to non-const.

On the other hand, I always make them members too. Given the
ubiquity of the idiom, it's best to go along with it, rather
than cause the reader to ask all sorts of questions.
 
N

Nephi Immortal

This looks like an excellent decision: making the conversion
constructor explicit, then overriding operator=.  On the other
hand, I'm just slightly sceptical about one thing: most of the
time when you implement a class, you want it's operators, and
not those of the built-in type, whenever the class is used.  The
presence of a user defined conversion operator means that you
risk getting just the opposite.  User defined conversion
operators tend to be very dangerous.  (I believe C++0x allows
them to be declared explicit.  This would alleviate most of the
danger.)


Just a nit, but if the operators aren't defined inline, why make
them friend?


The usual convention is for the first to to be members, not
friends (although IMHO, there is a good argument for making them
non-members, but with a non-const left parameter).  As for the
last, it's probably irrelevant, since the it is covered by the
builtin operator += and the conversion operator.

At any rate, += should modify it's left arguement, so passing it
a reference to const is out.


Given the definition of the last three, I'd just let the
compiler take care of them (with perhaps a comment saying that
the compiler provided defaults are used).






Given these definitions, why friend?


This is very dubious.  A += operator which doesn't modify the
left argument?  I'd call this operator overloading abuse, and
very, very poor design.






It's almost always an error to have a reference as a data
member.  And I can't think of a single exception when the class
has value semantics, as is the case here.  Value semantics imply
both copy and assignment, and that both have roughly the same
semantics.  Which isn't possible with reference members.




Note that this could have very undesirable semantics because of
the reference member.  You could end up modifying the value of
right.


James,

Please review previous thread at
http://groups.google.com/group/comp...?hl=en&lnk=gst&q=Paul+Bibbings+ImmortalNephi#..
Paul Bibbings talked about proxy class and operator cast returns
reference. I posted RGB Array class eight months ago. It is very
similar what I am talking about operator+ here.
Byte class is the similar to class B that takes constructor and data
member by reference. He said not to use copy constructor if proxy
class is used or it will have undefined behavior.
I am confused when you said. This code is abused if proxy class is
used.

Nephi
 
J

James Kanze

On Feb 20, 8:17 am, James Kanze <[email protected]> wrote:

[...]
Please review previous thread athttp://groups.google.com/group/comp.lang.c++/browse_thread/thread/5c5....

It's really too long for me to study it in detail, however...
Paul Bibbings talked about proxy class and operator cast returns
reference. I posted RGB Array class eight months ago. It is very
similar what I am talking about operator+ here.
Byte class is the similar to class B that takes constructor and data
member by reference. He said not to use copy constructor if proxy
class is used or it will have undefined behavior.
I am confused when you said. This code is abused if proxy class is
used.

It's not clear to me here what is a proxy for what, but
generally, when proxies are used, the proxy class will contain
a pointer, and not a reference. (And proxy classes don't always
support operator=, although mine usually do.)
 

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,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top