Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   How to use reference to do cast operator? (http://www.velocityreviews.com/forums/t728614-how-to-use-reference-to-do-cast-operator.html)

Immortal Nephi 07-19-2010 01:20 AM

How to use reference to do cast operator?
 
I write two different classes. Two classes have their own memory
that holds data in array. They can have different algorithms to
manipulate data.
I would like to write my code to transfer data between two classes.
First class has tasks to process data before it can transfer data to
second class. After the data transfer is complete, both classes use
their own algorithms to manipulate data.
My code looks like that:

int main() {
Class_A a;
Class_B b;

a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );

b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );

for( int x = 0; x < 4; x++ )
a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
b.Get_3( x ) );

return 0;
}

Do you notice for loop? For loop transfers data from class b to
class a. I decide to replace from for loop to cast operator. You can
write that code like this.

// for( int x = 0; x < 4; x++ )
// a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
b.Get_3( x ) );

a = b; // class b is converted to class a by moving data

The cast operator function looks like:

Class_B::operator Class_A () {
Class_A a;

for( int x = 0; x < 4; x++ )
a.Set_1( x, m_Data_1[ x ] ).Set_2( x, m_Data_2[ x ] ).Set_3( x,
m_Data_3[ x ] );

return a;
}

It is possible that transferring data between memory can cause
overhead because cast operator creates temporary class a in memory
before data transfer begins. After cast operator function terminates,
temporary class a is created second time because it uses copy
constructor.
After copy constructor is completed, temporary class a is
deallocated. Return to the main() function, temporary class a for
copy constructor is deallocated.
You can see that data transfer requires temporary class a twice. How
do you use reference? Reference can avoid reallocate memory twice.
Sometimes, I want to use operator[] to select element in the array in
class b and transfers it to class a rather than copying all data in
memory.

for( int x = 0; x < 4; x++ )
a[ x ] = b[ x ]; // use operator [] to do cast operator

// a = b; // All elements from class b is transferred to class a
without using operator[]

I canít think how to add operator[] to both class a and class b.
Maybe, proxy class is needed. I tried to write operator[] function
but it did not work.

You can examine complete code below if you wish.

class Class_A;
class Class_B;

class Class_A {
public:
Class_A();
Class_A( const Class_A &class_a );
~Class_A();

Class_A &Set_1( int index, unsigned char value );
Class_A &Set_2( int index, unsigned char value );
Class_A &Set_3( int index, unsigned char value );

unsigned char Get_1( int index );
unsigned char Get_2( int index );
unsigned char Get_3( int index );

operator Class_B ();

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
};

class Class_B {
public:
Class_B();
Class_B( const Class_B &class_b );
~Class_B();

Class_B &Set_1( int index, unsigned char value );
Class_B &Set_2( int index, unsigned char value );
Class_B &Set_3( int index, unsigned char value );

unsigned char Get_1( int index );
unsigned char Get_2( int index );
unsigned char Get_3( int index );

operator Class_A ();

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
};

Class_A::Class_A() {
for( int x = 0; x < 4; x++ )
m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;
}

Class_A::Class_A( const Class_A &class_a ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_a.m_Data_1[ x ];
m_Data_2[ x ] = class_a.m_Data_2[ x ];
m_Data_3[ x ] = class_a.m_Data_3[ x ];
}
}

Class_A::~Class_A() {
}

Class_A &Class_A::Set_1( int index, unsigned char value ) {
m_Data_1[ index ] = value;
return *this;
}

Class_A &Class_A::Set_2( int index, unsigned char value ) {
m_Data_2[ index ] = value;
return *this;
}

Class_A &Class_A::Set_3( int index, unsigned char value ) {
m_Data_3[ index ] = value;
return *this;
}

unsigned char Class_A::Get_1( int index ) {
return m_Data_1[ index ];
}

unsigned char Class_A::Get_2( int index ) {
return m_Data_2[ index ];
}

unsigned char Class_A::Get_3( int index ) {
return m_Data_3[ index ];
}

Class_A::operator Class_B () {
Class_B b;

for( int x = 0; x < 4; x++ )
b.Set_1( x, m_Data_1[ x ] ).Set_2( x, m_Data_2[ x ] ).Set_3( x,
m_Data_3[ x ] );

return b;
}


Class_B::Class_B() {
for( int x = 0; x < 4; x++ )
m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;
}

Class_B::Class_B( const Class_B &class_b ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_b.m_Data_1[ x ];
m_Data_2[ x ] = class_b.m_Data_2[ x ];
m_Data_3[ x ] = class_b.m_Data_3[ x ];
}
}

Class_B::~Class_B() {
}

Class_B &Class_B::Set_1( int index, unsigned char value ) {
m_Data_1[ index ] = value;
return *this;
}

Class_B &Class_B::Set_2( int index, unsigned char value ) {
m_Data_2[ index ] = value;
return *this;
}

Class_B &Class_B::Set_3( int index, unsigned char value ) {
m_Data_3[ index ] = value;
return *this;
}

unsigned char Class_B::Get_1( int index ) {
return m_Data_1[ index ];
}

unsigned char Class_B::Get_2( int index ) {
return m_Data_2[ index ];
}

unsigned char Class_B::Get_3( int index ) {
return m_Data_3[ index ];
}

Class_B::operator Class_A () {
Class_A a;

for( int x = 0; x < 4; x++ )
a.Set_1( x, m_Data_1[ x ] ).Set_2( x, m_Data_2[ x ] ).Set_3( x,
m_Data_3[ x ] );

return a;
}


int main() {
Class_A a;
Class_B b;

a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );

b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );

// First method
for( int x = 0; x < 4; x++ )
a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
b.Get_3( x ) );

// Second method
a = b;

// Third method
for( int x = 0; x < 4; x++ )
a[ x ] = b[ x ];

return 0;
}

Francesco S. Carta 07-19-2010 02:13 AM

Re: How to use reference to do cast operator?
 
Immortal Nephi <Immortal_Nephi@hotmail.com>, on 18/07/2010 18:20:18, wrote:

> I write two different classes. Two classes have their own memory
> that holds data in array. They can have different algorithms to
> manipulate data.
> I would like to write my code to transfer data between two classes.
> First class has tasks to process data before it can transfer data to
> second class. After the data transfer is complete, both classes use
> their own algorithms to manipulate data.



I see two steps here above:

- process the data in the first class (and I would do that either in the
construction step or in the first call to the getter function)

- transfer the data to the second class (and I would do it with an
assignment operator that takes a const reference to the first class)

Implementing the second step as an assignment operator has the advantage
of not having to worry about temporaries, assigning directly to the
private data of the class that is being assigned to.


> My code looks like that:
>
> int main() {
> Class_A a;
> Class_B b;
>
> a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
> a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
> a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
> a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );
>
> b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
> b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
> b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
> b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );
>
> for( int x = 0; x< 4; x++ )
> a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
> b.Get_3( x ) );
>
> return 0;
> }
>
> Do you notice for loop? For loop transfers data from class b to
> class a. I decide to replace from for loop to cast operator. You can
> write that code like this.
>
> // for( int x = 0; x< 4; x++ )
> // a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
> b.Get_3( x ) );
>
> a = b; // class b is converted to class a by moving data
>
> The cast operator function looks like:
>
> Class_B::operator Class_A () {
> Class_A a;
>
> for( int x = 0; x< 4; x++ )
> a.Set_1( x, m_Data_1[ x ] ).Set_2( x, m_Data_2[ x ] ).Set_3( x,
> m_Data_3[ x ] );
>
> return a;
> }
>
> It is possible that transferring data between memory can cause
> overhead because cast operator creates temporary class a in memory
> before data transfer begins. After cast operator function terminates,
> temporary class a is created second time because it uses copy
> constructor.



Temporaries may be optimized out by the compiler, depending on the
cases. I don't think you really need a conversion operator (the one you
call "cast" operator) - the assignment operator I mentioned above should
be more efficient - unless, maybe, if the class needs special care in
case of self-assignment, which seems not to be your case.


> After copy constructor is completed, temporary class a is
> deallocated. Return to the main() function, temporary class a for
> copy constructor is deallocated.
> You can see that data transfer requires temporary class a twice. How
> do you use reference? Reference can avoid reallocate memory twice.
> Sometimes, I want to use operator[] to select element in the array in
> class b and transfers it to class a rather than copying all data in
> memory.
>
> for( int x = 0; x< 4; x++ )
> a[ x ] = b[ x ]; // use operator [] to do cast operator
>
> // a = b; // All elements from class b is transferred to class a
> without using operator[]
>
> I canít think how to add operator[] to both class a and class b.
> Maybe, proxy class is needed. I tried to write operator[] function
> but it did not work.
>



You didn't post your operator[], which was the problem? I don't think
there should be any problem in implementing it for both of your classes.


--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com

Immortal Nephi 07-20-2010 09:45 PM

Re: How to use reference to do cast operator?
 
On Jul 18, 9:13*pm, "Francesco S. Carta" <entul...@gmail.com> wrote:
> Immortal Nephi <Immortal_Ne...@hotmail.com>, on 18/07/2010 18:20:18, wrote:
>
> > * *I write two different classes. *Two classes have their own memory
> > that holds data in array. *They can have different algorithms to
> > manipulate data.
> > * *I would like to write my code to transfer data between two classes.
> > First class has tasks to process data before it can transfer data to
> > second class. *After the data transfer is complete, both classes use
> > their own algorithms to manipulate data.

>
> I see two steps here above:
>
> - process the data in the first class (and I would do that either in the
> construction step or in the first call to the getter function)
>
> - transfer the data to the second class (and I would do it with an
> assignment operator that takes a const reference to the first class)
>
> Implementing the second step as an assignment operator has the advantage
> of not having to worry about temporaries, assigning directly to the
> private data of the class that is being assigned to.
>
>
>
>
>
> > * *My code looks like that:

>
> > int main() {
> > * *Class_A a;
> > * *Class_B b;

>
> > * *a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
> > * *a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
> > * *a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
> > * *a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );

>
> > * *b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
> > * *b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
> > * *b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
> > * *b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );

>
> > * *for( int x = 0; x< *4; x++ )
> > * * * * * *a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
> > b.Get_3( x ) );

>
> > * *return 0;
> > }

>
> > * *Do you notice for loop? *For loop transfers data from class b to
> > class a. *I decide to replace from for loop to cast operator. *You can
> > write that code like this.

>
> > // for( int x = 0; x< *4; x++ )
> > // * * * * a.Set_1( x, b.Get_1( x ) ).Set_2( x, b.Get_2( x ) ).Set_3( x,
> > b.Get_3( x ) );

>
> > * *a = b; // class b is converted to class a by moving data

>
> > * *The cast operator function looks like:

>
> > Class_B::operator Class_A () {
> > * *Class_A a;

>
> > * *for( int x = 0; x< *4; x++ )
> > * * * * * *a.Set_1( x, m_Data_1[ x ] ).Set_2( x, m_Data_2[ x ] ).Set_3( x,
> > m_Data_3[ x ] );

>
> > * *return a;
> > }

>
> > * *It is possible that transferring data between memory can cause
> > overhead because cast operator creates temporary class a in memory
> > before data transfer begins. *After cast operator function terminates,
> > temporary class a is created second time because it uses copy
> > constructor.

>
> Temporaries may be optimized out by the compiler, depending on the
> cases. I don't think you really need a conversion operator (the one you
> call "cast" operator) - the assignment operator I mentioned above should
> be more efficient - unless, maybe, if the class needs special care in
> case of self-assignment, which seems not to be your case.
>
>
>
>
>
> > * *After copy constructor is completed, temporary class a is
> > deallocated. *Return to the main() function, temporary class a for
> > copy constructor is deallocated.
> > * *You can see that data transfer requires temporary class a twice. *How
> > do you use reference? *Reference can avoid reallocate memory twice.
> > * *Sometimes, I want to use operator[] to select element in the array in
> > class b and transfers it to class a rather than copying all data in
> > memory.

>
> > * *for( int x = 0; x< *4; x++ )
> > * * * * * *a[ x ] = b[ x ]; // use operator [] to do cast operator

>
> > // a = b; // All elements from class b is transferred to class a
> > without using operator[]

>
> > * *I canít think how to add operator[] to both class a and class b.
> > Maybe, proxy class is needed. *I tried to write operator[] function
> > but it did not work.

>
> You didn't post your operator[], which was the problem? I don't think
> there should be any problem in implementing it for both of your classes.
>


You explain very well how operator= works. I add operator[] to both
class A and class B. I add reference on both classes to the return
type.
After operator[] receives index, it copies index into data member and
then returns class A reference.
You may find out the trick. Please look at my code. Let me know
what you think?

class Class_A;
class Class_B;

class Class_A {
friend Class_B;
public:
Class_A();
Class_A( const Class_A &class_a );
~Class_A();

Class_A &Set_1( int index, unsigned char value );
Class_A &Set_2( int index, unsigned char value );
Class_A &Set_3( int index, unsigned char value );

unsigned char Get_1( int index );
unsigned char Get_2( int index );
unsigned char Get_3( int index );

Class_A &operator=( Class_B &class_b );
Class_A &operator[]( int index );

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
int m_Index;
bool m_All;
};

class Class_B {
friend Class_A;
public:
Class_B();
Class_B( const Class_B &class_b );
~Class_B();

Class_B &Set_1( int index, unsigned char value );
Class_B &Set_2( int index, unsigned char value );
Class_B &Set_3( int index, unsigned char value );

unsigned char Get_1( int index );
unsigned char Get_2( int index );
unsigned char Get_3( int index );

Class_B &operator=( Class_A &class_a );
Class_B &operator[]( int index );

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
int m_Index;
bool m_All;
};

Class_A::Class_A() {
for( int x = 0; x < 4; x++ )
m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;

m_Index = 0;
m_All = true;
}

Class_A::Class_A( const Class_A &class_a ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_a.m_Data_1[ x ];
m_Data_2[ x ] = class_a.m_Data_2[ x ];
m_Data_3[ x ] = class_a.m_Data_3[ x ];
}
}

Class_A::~Class_A() {
}

Class_A &Class_A::Set_1( int index, unsigned char value ) {
m_Data_1[ index ] = value;
return *this;
}

Class_A &Class_A::Set_2( int index, unsigned char value ) {
m_Data_2[ index ] = value;
return *this;
}

Class_A &Class_A::Set_3( int index, unsigned char value ) {
m_Data_3[ index ] = value;
return *this;
}

unsigned char Class_A::Get_1( int index ) {
return m_Data_1[ index ];
}

unsigned char Class_A::Get_2( int index ) {
return m_Data_2[ index ];
}

unsigned char Class_A::Get_3( int index ) {
return m_Data_3[ index ];
}

Class_A &Class_A::operator=( Class_B &class_b ) {
if( m_All == class_b.m_All ) {
if( class_b.m_All == true ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_b.m_Data_1[ x ];
m_Data_2[ x ] = class_b.m_Data_2[ x ];
m_Data_3[ x ] = class_b.m_Data_3[ x ];
}
}
else {
m_Data_1[ m_Index ] = class_b.m_Data_1[ class_b.m_Index ];
m_Data_2[ m_Index ] = class_b.m_Data_2[ class_b.m_Index ];
m_Data_3[ m_Index ] = class_b.m_Data_3[ class_b.m_Index ];

m_All = class_b.m_All = true;
}
}
else {
// Do nothing -- invalid example
// Class_A[ 1 ] = Class_B
// Class_A = Class_B[ 2 ]
m_All = class_b.m_All = true;
}

return *this;
}

Class_A &Class_A::operator[]( int index ) {
m_Index = index;
m_All = false;
return *this;
}

Class_B::Class_B() {
for( int x = 0; x < 4; x++ )
m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;

m_Index = 0;
m_All = true;
}

Class_B::Class_B( const Class_B &class_b ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_b.m_Data_1[ x ];
m_Data_2[ x ] = class_b.m_Data_2[ x ];
m_Data_3[ x ] = class_b.m_Data_3[ x ];
}
}

Class_B::~Class_B() {
}

Class_B &Class_B::Set_1( int index, unsigned char value ) {
m_Data_1[ index ] = value;
return *this;
}

Class_B &Class_B::Set_2( int index, unsigned char value ) {
m_Data_2[ index ] = value;
return *this;
}

Class_B &Class_B::Set_3( int index, unsigned char value ) {
m_Data_3[ index ] = value;
return *this;
}

unsigned char Class_B::Get_1( int index ) {
return m_Data_1[ index ];
}

unsigned char Class_B::Get_2( int index ) {
return m_Data_2[ index ];
}

unsigned char Class_B::Get_3( int index ) {
return m_Data_3[ index ];
}

Class_B &Class_B::operator=( Class_A &class_a ) {
if( m_All == class_a.m_All ) {
if( class_a.m_All == true ) {
for( int x = 0; x < 4; x++ ) {
m_Data_1[ x ] = class_a.m_Data_1[ x ];
m_Data_2[ x ] = class_a.m_Data_2[ x ];
m_Data_3[ x ] = class_a.m_Data_3[ x ];
}
}
else {
m_Data_1[ m_Index ] = class_a.m_Data_1[ class_a.m_Index ];
m_Data_2[ m_Index ] = class_a.m_Data_2[ class_a.m_Index ];
m_Data_3[ m_Index ] = class_a.m_Data_3[ class_a.m_Index ];

m_All = class_a.m_All = true;
}
}
else {
m_All = class_a.m_All = true;
// Do nothing -- invalid example
// Class_A[ 1 ] = Class_B
// Class_A = Class_B[ 2 ]
}

return *this;
}

Class_B &Class_B::operator[]( int index ) {
m_Index = index;
m_All = false;
return *this;
}

int main() {
Class_A a;
Class_B b;

a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );

b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );

a[ 1 ] = b[ 2 ];
a = b;

// Do nothing -- invalid example
a[ 1 ] = b;
a = b[ 2 ];
b[ 3 ] = a;

return 0;
}

Francesco S. Carta 07-20-2010 11:24 PM

Re: How to use reference to do cast operator?
 
Immortal Nephi <Immortal_Nephi@hotmail.com>, on 20/07/2010 14:45:22, wrote:

> On Jul 18, 9:13 pm, "Francesco S. Carta"<entul...@gmail.com> wrote:
>> Immortal Nephi<Immortal_Ne...@hotmail.com>, on 18/07/2010 18:20:18, wrote:


<large snip>

>>> I canít think how to add operator[] to both class a and class b.
>>> Maybe, proxy class is needed. I tried to write operator[] function
>>> but it did not work.

>>
>> You didn't post your operator[], which was the problem? I don't think
>> there should be any problem in implementing it for both of your classes.
>>

>
> You explain very well how operator= works. I add operator[] to both
> class A and class B. I add reference on both classes to the return
> type.
> After operator[] receives index, it copies index into data member and
> then returns class A reference.
> You may find out the trick. Please look at my code. Let me know
> what you think?


<snip code>

I see the trick you implemented, it can be a good idea but you did not
implement it very well.

You left room for a lot of nonsensical instructions which lead to either
no effect or misleading effect.

If an operation is not supported, you have to stop it at compile time,
so that the client code understands it's doing something that is not
expected to work - if your interface "seems" to support an operation but
in fact does just a no-op, that's just bad design.

If an operation can not be executed with some inappropriate input, you
have to intercept that wrong input and either throw an exception or do a
no-op returning some kind of error flag.

As it is, your code allows these bad instructions:

a.Set_1(42, 10);

The above is bad because writes out of the array boundaries, leading to
a wide series of well known problems. Always check the input before
feeding it as an array index.

a[1][2] = b[1][2];

The above is bad because only the second series gets copied, while
somebody could think that also the first series will - and it won't.

The solution to the above problem could be to /not/ return a Class_X&
from the subscript operator, but instead some different proxy class that
ensure the appropriate number and sequence of subscript operators - I
wouldn't consider implementing such proxies as a really easy task, but
maybe that's just due to my limited experience about this subject.

There is another issue with your class(es): duplicate code - a problem
into which I happen to fall quite often when starting a new program.

If those classes share almost all the interface (and the underlying
data) all of this should be done with some common base class.

(if it were my code, I would also get rid of the duplicate code that
deals with those three arrays by putting them together in a further
array, accessing them by index instead that by different names as you
do... but if it were my code I would also use vectors instead of arrays)

The mixed uppercase/lowercase/underscore naming style is quite weird to
my eyes, but this last issue is just matter of style/tastes.

Well, you asked for my opinion, sorry if it seems too bad as a
dissection, I learnt to take the good things from such kind of replies,
when somebody else dissected my code - I hope you'll be able to do the
same with my reply.

Have nice time coding with C++

--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com

Immortal Nephi 07-21-2010 12:50 AM

Re: How to use reference to do cast operator?
 
On Jul 20, 6:24*pm, "Francesco S. Carta" <entul...@gmail.com> wrote:
> Immortal Nephi <Immortal_Ne...@hotmail.com>, on 20/07/2010 14:45:22, wrote:
>
> > On Jul 18, 9:13 pm, "Francesco S. Carta"<entul...@gmail.com> *wrote:
> >> Immortal Nephi<Immortal_Ne...@hotmail.com>, on 18/07/2010 18:20:18, wrote:

>
> <large snip>
>
> >>> * * I canít think how to add operator[] to both class a and class b.
> >>> Maybe, proxy class is needed. *I tried to write operator[] function
> >>> but it did not work.

>
> >> You didn't post your operator[], which was the problem? I don't think
> >> there should be any problem in implementing it for both of your classes.

>
> > * *You explain very well how operator= works. *I add operator[] to both
> > class A and class B. *I add reference on both classes to the return
> > type.
> > * *After operator[] receives index, it copies index into data member and
> > then returns class A reference.
> > * *You may find out the trick. *Please look at my code. *Let me know
> > what you think?

>
> <snip code>
>
> I see the trick you implemented, it can be a good idea but you did not
> implement it very well.
>
> You left room for a lot of nonsensical instructions which lead to either
> no effect or misleading effect.
>
> If an operation is not supported, you have to stop it at compile time,
> so that the client code understands it's doing something that is not
> expected to work - if your interface "seems" to support an operation but
> in fact does just a no-op, that's just bad design.


Well, you want flexibility. What choice do you want? Design only
one class. The design is flawed. Always design small class when
debug is easier to be tested.
Define more than 5 classes. Group them into namespace. There are
many different format designs such as graphics, word processor, or
file types.
Write good documentation. Give it to the programmers. The
programmers know how to use code when they read documentation.
Do you want to write one class name to do conversion?

class ObjectToObject {
// Ö
};

Maybe, you donít want to do that.

class Object_A {
// Ö
};

class Object_B {
// Ö
};

Object_A a;
Object_B b;

a = b;

a[ x ] = b[ x ];

Readability looks much easier to understand when you see variable
names.


> If an operation can not be executed with some inappropriate input, you
> have to intercept that wrong input and either throw an exception or do a
> no-op returning some kind of error flag.
>
> As it is, your code allows these bad instructions:
>
> a.Set_1(42, 10);
>
> The above is bad because writes out of the array boundaries, leading to
> a wide series of well known problems. Always check the input before
> feeding it as an array index.


You do not need to do input check on subscript out of range if
library is in release mode. You can always use assert to do input
check in debug mode.

>
> a[1][2] = b[1][2];
>
> The above is bad because only the second series gets copied, while
> somebody could think that also the first series will - and it won't.
>
> The solution to the above problem could be to /not/ return a Class_X&
> from the subscript operator, but instead some different proxy class that
> ensure the appropriate number and sequence of subscript operators - I
> wouldn't consider implementing such proxies as a really easy task, but
> maybe that's just due to my limited experience about this subject.


Put three separate arrays into one array is bad idea because each
array have different data types. To transfer data between two classes
is the best when you want to index element in three arrays on the same
time.

> There is another issue with your class(es): duplicate code - a problem
> into which I happen to fall quite often when starting a new program.
>
> If those classes share almost all the interface (and the underlying
> data) all of this should be done with some common base class.


> (if it were my code, I would also get rid of the duplicate code that
> deals with those three arrays by putting them together in a further
> array, accessing them by index instead that by different names as you
> do... but if it were my code I would also use vectors instead of arrays)


Sometimes, several classes have duplicate codes. Inheritance may be
bad idea because internal data structures are different. Sometimes,
you choose to use vector if you want to manipulate group of arrays.
Different internal data structures cannot be shared between classes
if they have different algorithms. First class uses algorithm to
process data before data is transferred to second class and then
second class receives data from first class to process different
algorithm.
You may not want to mix all algorithms into one class.


> The mixed uppercase/lowercase/underscore naming style is quite weird to
> my eyes, but this last issue is just matter of style/tastes.
>
> Well, you asked for my opinion, sorry if it seems too bad as a
> dissection, I learnt to take the good things from such kind of replies,
> when somebody else dissected my code - I hope you'll be able to do the
> same with my reply.


Francesco S. Carta 07-21-2010 01:46 AM

Re: How to use reference to do cast operator?
 
Immortal Nephi <Immortal_Nephi@hotmail.com>, on 20/07/2010 17:50:49, wrote:

> On Jul 20, 6:24 pm, "Francesco S. Carta"<entul...@gmail.com> wrote:
>> Immortal Nephi<Immortal_Ne...@hotmail.com>, on 20/07/2010 14:45:22, wrote:
>>
>>> On Jul 18, 9:13 pm, "Francesco S. Carta"<entul...@gmail.com> wrote:
>>>> Immortal Nephi<Immortal_Ne...@hotmail.com>, on 18/07/2010 18:20:18, wrote:

>>
>> <large snip>
>>
>>>>> I canít think how to add operator[] to both class a and class b.
>>>>> Maybe, proxy class is needed. I tried to write operator[] function
>>>>> but it did not work.

>>
>>>> You didn't post your operator[], which was the problem? I don't think
>>>> there should be any problem in implementing it for both of your classes.

>>
>>> You explain very well how operator= works. I add operator[] to both
>>> class A and class B. I add reference on both classes to the return
>>> type.
>>> After operator[] receives index, it copies index into data member and
>>> then returns class A reference.
>>> You may find out the trick. Please look at my code. Let me know
>>> what you think?

>>
>> <snip code>
>>
>> I see the trick you implemented, it can be a good idea but you did not
>> implement it very well.
>>
>> You left room for a lot of nonsensical instructions which lead to either
>> no effect or misleading effect.
>>
>> If an operation is not supported, you have to stop it at compile time,
>> so that the client code understands it's doing something that is not
>> expected to work - if your interface "seems" to support an operation but
>> in fact does just a no-op, that's just bad design.

>
> Well, you want flexibility. What choice do you want? Design only
> one class. The design is flawed. Always design small class when
> debug is easier to be tested.
> Define more than 5 classes. Group them into namespace. There are
> many different format designs such as graphics, word processor, or
> file types.
> Write good documentation. Give it to the programmers. The
> programmers know how to use code when they read documentation.
> Do you want to write one class name to do conversion?
>
> class ObjectToObject {
> // Ö
> };
>
> Maybe, you donít want to do that.
>
> class Object_A {
> // Ö
> };
>
> class Object_B {
> // Ö
> };
>
> Object_A a;
> Object_B b;
>
> a = b;
>
> a[ x ] = b[ x ];
>
> Readability looks much easier to understand when you see variable
> names.
>



And messages look much easier to understand when phrases and paragraphs
follow some kind of logical reasoning, possibly following up to the
context they're replying to.

In other words, I am not able to see what all the above has to deal with
my assertion that your interfaces should allow only meaningful
operations - unless we speak about over-abundant interfaces (or whatever
they're called in English) meant to be used as base classes for
different other classes, but this is another pair of legs, and a pair of
legs that I don't really like.


>
>> If an operation can not be executed with some inappropriate input, you
>> have to intercept that wrong input and either throw an exception or do a
>> no-op returning some kind of error flag.
>>
>> As it is, your code allows these bad instructions:
>>
>> a.Set_1(42, 10);
>>
>> The above is bad because writes out of the array boundaries, leading to
>> a wide series of well known problems. Always check the input before
>> feeding it as an array index.

>
> You do not need to do input check on subscript out of range if
> library is in release mode. You can always use assert to do input
> check in debug mode.



Writing out of the array boundaries is something you have to avoid by
enforcing checks in your code whenever the index comes from client code
- that is, whenever you aren't 100% sure that the index is within the
valid range.

The build mode, either "release" or "debug", has nothing to do with this
issue.

For the sake of context, this was your private array definition:

unsigned char m_Data_1[ 4 ];

and this was your public setter:

Class_A &Class_A::Set_1( int index, unsigned char value ) {
m_Data_1[ index ] = value;
return *this;
}

The above is bad code, period.

But if you are happy with a program/library that crashes, terminates or
misbehaves after that an user mistypes a value, well that's your
prerogative.


>>
>> a[1][2] = b[1][2];
>>
>> The above is bad because only the second series gets copied, while
>> somebody could think that also the first series will - and it won't.
>>
>> The solution to the above problem could be to /not/ return a Class_X&
>> from the subscript operator, but instead some different proxy class that
>> ensure the appropriate number and sequence of subscript operators - I
>> wouldn't consider implementing such proxies as a really easy task, but
>> maybe that's just due to my limited experience about this subject.

>
> Put three separate arrays into one array is bad idea because each
> array have different data types. To transfer data between two classes
> is the best when you want to index element in three arrays on the same
> time.



Apart that you mixed up your reply sections (the part you're replying to
appears further down) what you said doesn't match with the code you
wrote. Both of your classes had the same exact data members, and all the
arrays had the same exact type.

Context, once more. These are the relevant parts of your code:

class Class_A {

// ...

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
int m_Index;
bool m_All;
};

class Class_B {

// ...

private:
unsigned char m_Data_1[ 4 ];
unsigned char m_Data_2[ 4 ];
unsigned char m_Data_3[ 4 ];
int m_Index;
bool m_All;
};


>
>> There is another issue with your class(es): duplicate code - a problem
>> into which I happen to fall quite often when starting a new program.
>>
>> If those classes share almost all the interface (and the underlying
>> data) all of this should be done with some common base class.

>
>> (if it were my code, I would also get rid of the duplicate code that
>> deals with those three arrays by putting them together in a further
>> array, accessing them by index instead that by different names as you
>> do... but if it were my code I would also use vectors instead of arrays)

>
> Sometimes, several classes have duplicate codes. Inheritance may be
> bad idea because internal data structures are different. Sometimes,
> you choose to use vector if you want to manipulate group of arrays.
> Different internal data structures cannot be shared between classes
> if they have different algorithms. First class uses algorithm to
> process data before data is transferred to second class and then
> second class receives data from first class to process different
> algorithm.
> You may not want to mix all algorithms into one class.



Once more, your internal data structures were identical to each other,
and you posted no algorithms apart from the copying ones.

The last classes you have posted can serenely be rewritten to share a
common interface and a common data structure, still having different
name and different type, and still they could use different algorithms
to manipulate their data.

But I see you're speaking in general or about some different code:
either post that code or simply drop the current one, depending on what
you want to discuss.

--
FSC - http://userscripts.org/scripts/show/59948
http://fscode.altervista.org - http://sardinias.com

Paul Bibbings 07-21-2010 10:22 AM

Re: How to use reference to do cast operator?
 
Immortal Nephi <Immortal_Nephi@hotmail.com> writes:
<snip />

> I can°Įt think how to add operator[] to both class a and class b.
> Maybe, proxy class is needed. I tried to write operator[] function
> but it did not work.
>
> You can examine complete code below if you wish.


Having seen your attempt at writing your op[] in a subsequent post I can
agree with a lot of the comments made by Francesco in relation to it.
Since you have mentioned the possibility of using a proxy class (and
since we have looked at these together before also) I have quickly
thrown together an example (very likely not ideal) to illustrate how
this might be done. Since your classes store what are effectively three
rows of four elements, I have implemented the proxy to manage `columns'
of three elements via a tr1::tuple. This may not be viable nor what you
want but, as I have said, this is just an example.

I present my example by making additions to the code you have already
given (below).

/***** CODE *****/

#include <tr1/tuple>

template<typename T>
class Column_Proxy {
template<typename U>
friend class Column_Proxy;
public:
typedef std::tr1::tuple< T&, T&, T& > column_t;
Column_Proxy( T& first, T& second, T& third )
: column( first, second, third )
{ }
template<typename U>
Column_Proxy& operator=( const Column_Proxy<U>& cp ) {
std::tr1::get< 0 >( column ) = std::tr1::get< 0 >( cp.column );
std::tr1::get< 1 >( column ) = std::tr1::get< 1 >( cp.column );
std::tr1::get< 2 >( column ) = std::tr1::get< 2 >( cp.column );
return *this;
}

operator column_t( ) { return column; }
operator column_t( ) const { return column; }
private:
column_t column;
};

// class Class_A; forward declaration of Class_A not needed
> class Class_B;
>
> class Class_A {
> public:
> Class_A();
> Class_A( const Class_A &class_a );
> ~Class_A();
>
> Class_A &Set_1( int index, unsigned char value );
> Class_A &Set_2( int index, unsigned char value );
> Class_A &Set_3( int index, unsigned char value );
>
> unsigned char Get_1( int index );
> unsigned char Get_2( int index );
> unsigned char Get_3( int index );
>
> operator Class_B ();


Column_Proxy< unsigned char > operator[ ] ( int i );
Column_Proxy< const unsigned char > operator[ ] ( int i ) const;

> private:
> unsigned char m_Data_1[ 4 ];
> unsigned char m_Data_2[ 4 ];
> unsigned char m_Data_3[ 4 ];
> };
>
> class Class_B {
> public:
> Class_B();
> Class_B( const Class_B &class_b );
> ~Class_B();
>
> Class_B &Set_1( int index, unsigned char value );
> Class_B &Set_2( int index, unsigned char value );
> Class_B &Set_3( int index, unsigned char value );
>
> unsigned char Get_1( int index );
> unsigned char Get_2( int index );
> unsigned char Get_3( int index );
>
> operator Class_A ();


Column_Proxy< unsigned char > operator[ ] ( int i );
Column_Proxy< const unsigned char > operator[ ] ( int i ) const;

> private:
> unsigned char m_Data_1[ 4 ];
> unsigned char m_Data_2[ 4 ];
> unsigned char m_Data_3[ 4 ];
> };
>
> Class_A::Class_A() {
> for( int x = 0; x < 4; x++ )
> m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;
> }
>
> Class_A::Class_A( const Class_A &class_a ) {
> for( int x = 0; x < 4; x++ ) {
> m_Data_1[ x ] = class_a.m_Data_1[ x ];
> m_Data_2[ x ] = class_a.m_Data_2[ x ];
> m_Data_3[ x ] = class_a.m_Data_3[ x ];
> }
> }
>
> Class_A::~Class_A() {
> }
>
> Class_A &Class_A::Set_1( int index, unsigned char value ) {
> m_Data_1[ index ] = value;
> return *this;
> }
>
> Class_A &Class_A::Set_2( int index, unsigned char value ) {
> m_Data_2[ index ] = value;
> return *this;
> }
>
> Class_A &Class_A::Set_3( int index, unsigned char value ) {
> m_Data_3[ index ] = value;
> return *this;
> }
>
> unsigned char Class_A::Get_1( int index ) {
> return m_Data_1[ index ];
> }
>
> unsigned char Class_A::Get_2( int index ) {
> return m_Data_2[ index ];
> }
>
> unsigned char Class_A::Get_3( int index ) {
> return m_Data_3[ index ];
> }
>
> Class_A::operator Class_B () {
> Class_B b;
>
> for( int x = 0; x < 4; x++ )
> b.Set_1( x, m_Data_1[ x ] )
> .Set_2( x, m_Data_2[ x ] )
> .Set_3( x, m_Data_3[ x ] );
>
> return b;
> }


Column_Proxy< unsigned char >
Class_A::operator[ ] ( int i ) {
return Column_Proxy< unsigned char >( m_Data_1[ i ],
m_Data_2[ i ],
m_Data_3[ i ]);
}

Column_Proxy< const unsigned char >
Class_A::operator[ ] ( int i ) const {
return Column_Proxy< const unsigned char >( m_Data_1[ i ],
m_Data_2[ i ],
m_Data_3[ i ]);
}


>
> Class_B::Class_B() {
> for( int x = 0; x < 4; x++ )
> m_Data_1[ x ] = m_Data_2[ x ] = m_Data_3[ x ] = 0;
> }
>
> Class_B::Class_B( const Class_B &class_b ) {
> for( int x = 0; x < 4; x++ ) {
> m_Data_1[ x ] = class_b.m_Data_1[ x ];
> m_Data_2[ x ] = class_b.m_Data_2[ x ];
> m_Data_3[ x ] = class_b.m_Data_3[ x ];
> }
> }
>
> Class_B::~Class_B() {
> }
>
> Class_B &Class_B::Set_1( int index, unsigned char value ) {
> m_Data_1[ index ] = value;
> return *this;
> }
>
> Class_B &Class_B::Set_2( int index, unsigned char value ) {
> m_Data_2[ index ] = value;
> return *this;
> }
>
> Class_B &Class_B::Set_3( int index, unsigned char value ) {
> m_Data_3[ index ] = value;
> return *this;
> }
>
> unsigned char Class_B::Get_1( int index ) {
> return m_Data_1[ index ];
> }
>
> unsigned char Class_B::Get_2( int index ) {
> return m_Data_2[ index ];
> }
>
> unsigned char Class_B::Get_3( int index ) {
> return m_Data_3[ index ];
> }
>
> Class_B::operator Class_A () {
> Class_A a;
>
> for( int x = 0; x < 4; x++ )
> a.Set_1( x, m_Data_1[ x ] )
> .Set_2( x, m_Data_2[ x ] )
> .Set_3( x, m_Data_3[ x ] );
>
> return a;
> }


Column_Proxy< unsigned char >
Class_B::operator[ ] ( int i ) {
return Column_Proxy< unsigned char >( m_Data_1[ i ],
m_Data_2[ i ],
m_Data_3[ i ] );
}

Column_Proxy< const unsigned char >
Class_B::operator[ ] ( int i ) const {
return Column_Proxy< const unsigned char >( m_Data_1[ i ],
m_Data_2[ i ],
m_Data_3[ i ] );
}

> int main() {
> Class_A a;
> Class_B b;
>
> a.Set_1( 0, 0x41 ).Set_2( 0, 0x42 ).Set_3( 0, 0x43 );
> a.Set_1( 1, 0x44 ).Set_2( 1, 0x45 ).Set_3( 1, 0x46 );
> a.Set_1( 2, 0x47 ).Set_2( 2, 0x48 ).Set_3( 2, 0x49 );
> a.Set_1( 3, 0x4a ).Set_2( 3, 0x4b ).Set_3( 3, 0x4c );
>
> b.Set_1( 0, 0x71 ).Set_2( 0, 0x72 ).Set_3( 0, 0x73 );
> b.Set_1( 1, 0x74 ).Set_2( 1, 0x75 ).Set_3( 1, 0x76 );
> b.Set_1( 2, 0x77 ).Set_2( 2, 0x78 ).Set_3( 2, 0x79 );
> b.Set_1( 3, 0x7a ).Set_2( 3, 0x7b ).Set_3( 3, 0x7c );
>
> // First method
> for( int x = 0; x < 4; x++ )
> a.Set_1( x, b.Get_1( x ) )
> .Set_2( x, b.Get_2( x ) )
> .Set_3( x, b.Get_3( x ) );
>
> // Second method
> a = b;
>
> // Third method
> for( int x = 0; x < 4; x++ )
> a[ x ] = b[ x ];
>
> return 0;
> }


/***** END CODE *****/

Just an idea.

Regards

Paul Bibbings


All times are GMT. The time now is 07:14 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.