By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,625 Members | 1,283 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,625 IT Pros & Developers. It's quick & easy.

help: class compile error

P: n/a
Hi,

I encountered the following compile error of c++ and hope to get your help.

test2.cpp: In member function `CTest CTest::operator+=(CTest&)':
test2.cpp:79: error: no match for 'operator=' in '*this =
CTest::operator+(CTest&)((+t2))'
test2.cpp:49: error: candidates are: CTest CTest::operator=(CTest&)
make: *** [test2.o] Error 1

I don't know why in the main function, "t2 = t1" is ok, but in the
operator += body, "*this = *this+t2" is wrong. What I am thinking is
that the compiler looks for *this+t2 first, which generate a new CTest
instance, and then copy to *this. What's the mistake I made?

The code is compiled succeedly in Visual C++. but not in linux g++ (3.3.3).

And also in Visual C++,
for ( int i = 0; ... ;.... )
defines a global int i. so I can use
for ( int i = 0; ... ;.... ) { ... }
for ( i = 0; ...;......) { ... }
but in linux g++, this is wrong. "i" is only alive in the for body. I
need to define "i" again in the 2nd for body. What's the update of this
grammar? Which one is the standard c++?

Thank you very much in advance for the help.

X

-----------------------------------------------------
source code below:

#include <iostream.h>

class CTest
{
private:
int iSize;
double *dElement;

public:
CTest( const int &size = 1);
CTest( CTest &t );
~CTest();

public:
CTest operator = ( CTest &t2 );

const int size(void) { return iSize; }
double &operator[]( const int &index ) { return dElement[index]; }

public:
CTest operator + ( CTest &t2 );
CTest operator += ( CTest &t2 );
};

// constrution
CTest::CTest( const int &size )
{
iSize = size;
dElement = new double[iSize];
for ( int i = 0; i < iSize; i++ ) dElement[i] = 0.0;
}

// copy constrution
CTest::CTest( CTest &t2 )
{
iSize = t2.size();
dElement = new double[iSize];
for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];
}

// destruction: release the allocated memory
CTest::~CTest()
{
if (dElement) delete[] dElement;
}

// copy operator
CTest CTest::operator = ( CTest &t2 )
{ // <======== line 49
if ( iSize != t2.size() ) // reallocate the memory
{
iSize = t2.size();
if (dElement) delete [] dElement;
dElement = new double[iSize];
}

for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];

return *this;
}

CTest CTest::operator + ( CTest &t2 )
{
if ( iSize != t2.size() )
{
// errorhandle
return *this; // to be changed
}

CTest sum(t2);

for ( int i = 0; i < iSize; i++ ) sum[i] += dElement[i];

return sum;
}

CTest CTest::operator += ( CTest &t2 )
{
*this = *this + t2; // <===== line 79. compile error

return *this;
}

// main function
main(void)
{
int N = 10;
CTest t1(N);

for ( int i = 0; i < N; i++ ) t1[i] = i;

CTest t2;

t2 = t1;

for ( int i = 0; i < N; i++ ) cout << (t1+t2)[i] << endl;

return 1;
}
Jul 22 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
On Fri, 09 Jul 2004 12:03:58 -0700, xuatla <xu****@gmail.com> wrote:
Hi,

I encountered the following compile error of c++ and hope to get your
help.
You will.

test2.cpp: In member function `CTest CTest::operator+=(CTest&)':
test2.cpp:79: error: no match for 'operator=' in '*this =
CTest::operator+(CTest&)((+t2))'
test2.cpp:49: error: candidates are: CTest CTest::operator=(CTest&)
make: *** [test2.o] Error 1

I don't know why in the main function, "t2 = t1" is ok, but in the
operator += body, "*this = *this+t2" is wrong. What I am thinking is
that the compiler looks for *this+t2 first, which generate a new CTest
instance, and then copy to *this. What's the mistake I made?

You are ignoring the issue of const. You cannot ignore const in C++.

The code is compiled succeedly in Visual C++. but not in linux
g++ (3.3.3).
That is because Visual C++ does not handle const correctly, but g++ does.

And also in Visual C++,
for ( int i = 0; ... ;.... )
defines a global int i. so I can use
for ( int i = 0; ... ;.... ) { ... }
for ( i = 0; ...;......) { ... }
but in linux g++, this is wrong. "i" is only alive in the for body. I
need to define "i" again in the 2nd for body. What's the update of this
grammar? Which one is the standard c++?
Again g++ is right. If you want to make Visual C++ do for loops correctly
the best way is with a macro

#define for if (0); else for

Put that at the top of your code and for loops will work the right way in
Visual C++ and g++.

Thank you very much in advance for the help.

Below are the corrections to your code, hopefully I get all the places
that you missed out const, and then I'l explain why missing out const
stopped your code from compiling.
X

-----------------------------------------------------
source code below:

#include <iostream.h>

class CTest
{
private:
int iSize;
double *dElement;

public:
CTest( const int &size = 1);
CTest( CTest &t );
CTest( const CTest &t );
~CTest();

public:
CTest operator = ( CTest &t2 );
CTest& operator = ( const CTest &t2 );

Note is best to declare operator= as returning a reference, but the
important thing is that the argument should be a const reference.

const int size(void) { return iSize; }
int size(void) const { return iSize; }

That was one time that you put const in the wrong place.
double &operator[]( const int &index ) { return dElement[index]; }

public:
CTest operator + ( CTest &t2 );
CTest operator + ( const CTest &t2 ) const;
CTest operator += ( CTest &t2 );
CTest& operator += ( const CTest &t2 );

Again it is best to declare operator+= as returning a reference, but again
the important thing is that the argument should be a const reference.
};

// constrution
CTest::CTest( const int &size )
{
iSize = size;
dElement = new double[iSize];
for ( int i = 0; i < iSize; i++ ) dElement[i] = 0.0;
}

// copy constrution
CTest::CTest( CTest &t2 )
CTest::CTest( const CTest &t2 )
{
iSize = t2.size();
dElement = new double[iSize];
for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];
}

// destruction: release the allocated memory
CTest::~CTest()
{
if (dElement) delete[] dElement;
}

// copy operator
CTest CTest::operator = ( CTest &t2 )
CTest& CTest::operator = ( const CTest &t2 )
{ // <======== line 49
if ( iSize != t2.size() ) // reallocate the memory
{
iSize = t2.size();
if (dElement) delete [] dElement;
dElement = new double[iSize];
}

for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];

return *this;
}

CTest CTest::operator + ( CTest &t2 )
CTest CTest::operator + ( const CTest &t2 ) const

But here returning a reference would be quite wrong. The difference is
that operator+ creates a new object and that must be returned by value.
However both the argument and the method itself should be declared const.
{
if ( iSize != t2.size() )
{
// errorhandle
return *this; // to be changed
}

CTest sum(t2);

for ( int i = 0; i < iSize; i++ ) sum[i] += dElement[i];

return sum;
}

CTest CTest::operator += ( CTest &t2 )
CTest& CTest::operator += ( const CTest &t2 )
{
*this = *this + t2; // <===== line 79. compile error

return *this;
}


Now why does const matter? There is a rule in C++ that you cannot bind a
temporary to a non-const reference. Look at this line again

*this = *this + t2;

The first thing that happens is that CTest::operator+ is called, that
creates and returns a CTest object. What is the name of that object?
Answer: it doesn't have one, any unnamed object is called a *temporary*.

The next this that happens is that CTest::operator=(CTest& t2) is called.
But t2 is a non-const reference and you are trying to call it with a
temporary. That is not allowed.

By changing CTest::operator=(CTest& t2) to CTest::operator=(const CTest&
t2) I've changed t2 from a non-const reference to a const reference, so
now you can call operator= with a temporary.

Any reference that is not being used to change the object it is refering
to should be declared const, any method that does not change the object it
belongs to should be declared const. You cannot ignore the issue of const
in C++ (unless you use a rubbish compiler like Visual C++).

john
Jul 22 '05 #2

P: n/a
xuatla wrote:
I encountered the following compile error of c++ and hope to get your help.

test2.cpp: In member function `CTest CTest::operator+=(CTest&)':
test2.cpp:79: error: no match for 'operator=' in '*this =
CTest::operator+(CTest&)((+t2))'
test2.cpp:49: error: candidates are: CTest CTest::operator=(CTest&)
make: *** [test2.o] Error 1

I don't know why in the main function, "t2 = t1" is ok, but in the
operator += body, "*this = *this+t2" is wrong. What I am thinking is
that the compiler looks for *this+t2 first, which generate a new CTest
instance, and then copy to *this. What's the mistake I made?

The code is compiled succeedly in Visual C++. but not in linux g++ (3.3.3).

And also in Visual C++,
for ( int i = 0; ... ;.... )
defines a global int i. so I can use
for ( int i = 0; ... ;.... ) { ... }
for ( i = 0; ...;......) { ... }
but in linux g++, this is wrong. "i" is only alive in the for body. I
need to define "i" again in the 2nd for body. What's the update of this
grammar? Which one is the standard c++?
If a variable is declared in the for statement, its scope is limited
to the for statement and its body. VC++ has it as "an extension",
otherwise known as the "for scope bug".

Thank you very much in advance for the help.

X

-----------------------------------------------------
source code below:

#include <iostream.h>
There is no such standard header. Use <iostream>

class CTest
{
private:
int iSize;
double *dElement;

public:
CTest( const int &size = 1);
Integers and other built-in types are usually better passed by
value. It's much simpler to understand:

CTest(int size = 1);
CTest( CTest &t );
Copy constructors _usually_ accept their arguments by a _const_
reference, unless they somehow _change_ the arguments.
CTest(CTest const&);
~CTest();

public:
CTest operator = ( CTest &t2 );
The _conventional_ operator= should return a _reference_ and also
take its argument by a _const_ reference (unless it intends to change
it somehow).

CTest& operator=(CTest const &);

const int size(void) { return iSize; }
Return value's cv-qualifiers are usually meaningless (and are not
used anyway). A member function that doesn't (and never should)
change its object should be declared 'const':

int size() const { return iSize; }
double &operator[]( const int &index ) { return dElement[index]; }
Again, passing a built-in type by reference is unnecessary:

double& operator[](int index) { return dElement[index]; }

public:
CTest operator + ( CTest &t2 );
Any operator that doesn't change its operands should take those
operands as 'const':

CTest operator +(CTest const& t2) const;
CTest operator += ( CTest &t2 );
Assignment operators _usually_ return a reference and if argument
is not intended to be changed, it should be const:

CTest& operator += (CTest const &t2);
};

// constrution
CTest::CTest( const int &size )
{
iSize = size;
dElement = new double[iSize];
Always prefer initialisation over assignment. Read the FAQ.
for ( int i = 0; i < iSize; i++ ) dElement[i] = 0.0;
}

// copy constrution
CTest::CTest( CTest &t2 )
See above about the change in the signature.
{
iSize = t2.size();
dElement = new double[iSize];
Same here -- initialise, not assign.
for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];
You have full access to 't2's contents, why make additional calls
to the operator[] here, when you simply could do

....... dElement[i] = t2.dElement[i];

?
}

// destruction: release the allocated memory
CTest::~CTest()
{
if (dElement) delete[] dElement;
No need to check for 'dElement's non-NULL-ness, just delete[].
Deleting a null pointer has no effect.
}

// copy operator
CTest CTest::operator = ( CTest &t2 )
{ // <======== line 49
if ( iSize != t2.size() ) // reallocate the memory
What if it's smaller? Is there still the need to reallocate?
{
iSize = t2.size();
if (dElement) delete [] dElement;
dElement = new double[iSize];
}

for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];
Again, you can access t2.dElement directly, no need to call the
operator[] for t2.

return *this;
}

CTest CTest::operator + ( CTest &t2 )
The type of function should change and the type of its argument.
See above.
{
if ( iSize != t2.size() )
{
// errorhandle
return *this; // to be changed
}

CTest sum(t2);

for ( int i = 0; i < iSize; i++ ) sum[i] += dElement[i];
Again, you could simply access sum.dElement directly here.

return sum;
}

CTest CTest::operator += ( CTest &t2 )
The return value type should change and the argument type. See
above.
{
*this = *this + t2; // <===== line 79. compile error

return *this;
}

// main function
main(void)
There are no implicit return types in C++.

int main()
{
int N = 10;
CTest t1(N);

for ( int i = 0; i < N; i++ ) t1[i] = i;

CTest t2;

t2 = t1;

for ( int i = 0; i < N; i++ ) cout << (t1+t2)[i] << endl;

return 1;
}


Fix it all up as I recommend and see if the error goes away.

Victor
Jul 22 '05 #3

P: n/a
Great. Thanks Victor Bazarov and John Harrison for the detail and
comprehensive explanation.

I corrected the code in your ways and now it goes through successfully.

I have some more questions about your answer.
CTest::CTest( const int &size )
{
iSize = size;
dElement = new double[iSize];

Always prefer initialization over assignment. Read the FAQ.


What does this mean? Can I do the initialization and assignment in other
way? Where can I get FAQ? Can you tell me how to get the "help" file for
c++ grammar. Not man g++ but the grammar help of c++. I mean the on disk
help.
for ( int i = 0; i < iSize; i++ ) dElement[i] = 0.0;
}
// copy operator
CTest CTest::operator = ( CTest &t2 )
{ // <======== line 49
if ( iSize != t2.size() ) // reallocate the memory

What if it's smaller? Is there still the need to reallocate?


If the size is smaller, then I can just change iSize but leave the
dElement unchanged. But what I concern is that if I don't release
dElement and reallocate it, then it may waste the memory. For example,
suppose
t1 = t2; //t1.size() = 100, t2.size() = 2;
then t1.dElement still occupies 100 double. Is it correct?

I designed this class because I am not familiar with "vector" in C++ and
I need to use this type frequently. In my code it's rare that the size
is decreased.
{
iSize = t2.size();
if (dElement) delete [] dElement; You mentioned that I dont need to judge whether dElement is NULL before
deleting it. Is true for all types pointer?
dElement = new double[iSize];
}

for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];
Now I know that I need to use t2.dElement[i] instead of t2[i] here. If I
use t2[i], then compile error: no operator [] for const CTest&.
if I use #include "iostream.h", then compiler will give the warning of
"deprecated or antiquated header". But it's just a warning and compile
still completed. I changed to the following as you suggested.

#include <iostream>
using namespace std;

Do I need to add "using namespace" always for such a head file usage?

Another question for the class. I tried to use "const CTest&" but failed
and was told I didn't define the const class type (now I learned from
your explanation). Then I tried the following
class CTest
{
.....
} const;

What's the meaning of such "const" class?

One more question about new and delete:

I use new to create a CTest. And then delete it. But it seems that the
deletion is not successful. When I print it, it's still there.

Do I need to define new and delete for class by myself?

// main function
int main(void)
{
int N = 10;
CTest t1(N);
int i;

for ( i = 0; i < N; i++ ) t1[i] = i;

CTest *t2 = new CTest;

*t2 = t1;

for ( i = 0; i < N; i++ ) cout << (t1+*t2)[i] << endl;

delete t2;

for ( i = 0; i < N; i++ ) cout << (*t2)[i] << endl;
// still print out t2.

return 1;
}

Thanks a lot for your kind help!

X

Victor Bazarov wrote: xuatla wrote:
I encountered the following compile error of c++ and hope to get your
help.

test2.cpp: In member function `CTest CTest::operator+=(CTest&)':
test2.cpp:79: error: no match for 'operator=' in '*this =
CTest::operator+(CTest&)((+t2))'
test2.cpp:49: error: candidates are: CTest CTest::operator=(CTest&)
make: *** [test2.o] Error 1

I don't know why in the main function, "t2 = t1" is ok, but in the
operator += body, "*this = *this+t2" is wrong. What I am thinking is
that the compiler looks for *this+t2 first, which generate a new CTest
instance, and then copy to *this. What's the mistake I made?

The code is compiled succeedly in Visual C++. but not in linux g++
(3.3.3).

And also in Visual C++,
for ( int i = 0; ... ;.... )
defines a global int i. so I can use
for ( int i = 0; ... ;.... ) { ... }
for ( i = 0; ...;......) { ... }
but in linux g++, this is wrong. "i" is only alive in the for body. I
need to define "i" again in the 2nd for body. What's the update of
this grammar? Which one is the standard c++?

If a variable is declared in the for statement, its scope is limited
to the for statement and its body. VC++ has it as "an extension",
otherwise known as the "for scope bug".

Thank you very much in advance for the help.

X

-----------------------------------------------------
source code below:

#include <iostream.h>

There is no such standard header. Use <iostream>

class CTest
{
private:
int iSize;
double *dElement;

public:
CTest( const int &size = 1);

Integers and other built-in types are usually better passed by
value. It's much simpler to understand:

CTest(int size = 1);
CTest( CTest &t );

Copy constructors _usually_ accept their arguments by a _const_
reference, unless they somehow _change_ the arguments.
CTest(CTest const&);
~CTest();

public:
CTest operator = ( CTest &t2 );

The _conventional_ operator= should return a _reference_ and also
take its argument by a _const_ reference (unless it intends to change
it somehow).

CTest& operator=(CTest const &);
const int size(void) { return iSize; }

Return value's cv-qualifiers are usually meaningless (and are not
used anyway). A member function that doesn't (and never should)
change its object should be declared 'const':

int size() const { return iSize; }
double &operator[]( const int &index ) { return dElement[index]; }

Again, passing a built-in type by reference is unnecessary:

double& operator[](int index) { return dElement[index]; }

public:
CTest operator + ( CTest &t2 );

Any operator that doesn't change its operands should take those
operands as 'const':

CTest operator +(CTest const& t2) const;
CTest operator += ( CTest &t2 );

Assignment operators _usually_ return a reference and if argument
is not intended to be changed, it should be const:

CTest& operator += (CTest const &t2);
};

// constrution
CTest::CTest( const int &size )
{
iSize = size;
dElement = new double[iSize];

Always prefer initialisation over assignment. Read the FAQ.
for ( int i = 0; i < iSize; i++ ) dElement[i] = 0.0;
}

// copy constrution
CTest::CTest( CTest &t2 )

See above about the change in the signature.
{
iSize = t2.size();
dElement = new double[iSize];

Same here -- initialise, not assign.
for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];

You have full access to 't2's contents, why make additional calls
to the operator[] here, when you simply could do

....... dElement[i] = t2.dElement[i];

?
}

// destruction: release the allocated memory
CTest::~CTest()
{
if (dElement) delete[] dElement;

No need to check for 'dElement's non-NULL-ness, just delete[].
Deleting a null pointer has no effect.
}

// copy operator
CTest CTest::operator = ( CTest &t2 )
{ // <======== line 49
if ( iSize != t2.size() ) // reallocate the memory

What if it's smaller? Is there still the need to reallocate?
{
iSize = t2.size();
if (dElement) delete [] dElement;
dElement = new double[iSize];
}

for ( int i = 0; i < iSize; i++ ) dElement[i] = t2[i];

Again, you can access t2.dElement directly, no need to call the
operator[] for t2.
return *this;
}

CTest CTest::operator + ( CTest &t2 )

The type of function should change and the type of its argument.
See above.
{
if ( iSize != t2.size() )
{ // errorhandle
return *this; // to be changed
}

CTest sum(t2);

for ( int i = 0; i < iSize; i++ ) sum[i] += dElement[i];

Again, you could simply access sum.dElement directly here.

return sum;
}

CTest CTest::operator += ( CTest &t2 )

The return value type should change and the argument type. See
above.
{
*this = *this + t2; // <===== line 79. compile error

return *this;
}

// main function
main(void)

There are no implicit return types in C++.

int main()
{
int N = 10; CTest t1(N);

for ( int i = 0; i < N; i++ ) t1[i] = i;
CTest t2;

t2 = t1;
for ( int i = 0; i < N; i++ ) cout << (t1+t2)[i] << endl;
return 1;
}

Fix it all up as I recommend and see if the error goes away.

Victor

Jul 22 '05 #4

P: n/a

"xuatla" <xu****@gmail.com> wrote in message
news:40************@gmail.com...
One more question about new and delete:

I use new to create a CTest. And then delete it. But it seems that the
deletion is not successful. When I print it, it's still there.

Do I need to define new and delete for class by myself?

// main function
int main(void)
{
int N = 10;
CTest t1(N);
int i;

for ( i = 0; i < N; i++ ) t1[i] = i;

CTest *t2 = new CTest;

*t2 = t1;

for ( i = 0; i < N; i++ ) cout << (t1+*t2)[i] << endl;

delete t2;

for ( i = 0; i < N; i++ ) cout << (*t2)[i] << endl;
// still print out t2.

return 1;
}

Thanks a lot for your kind help!

X


Once you call delete on the pointer t2, it is illegal to use that pointer
(unless you assign it to another valid object first). What you are doing
*may* work in some cases (because it is *possible* that the memory at that
location has not changed...yet). But you can *never* rely on doing that
successfully. You are invoking "undefined behavior", which means that
anything can happen. It may work, it may crash, and it may even cause
*serious* problems! Simply put, "don't do that!" :-)

By the way, calling delete does not cause the computer to go to that memory
location and erase anything. What it does (well, one of the things it does,
somehow, behind the scenes), is mark the memory as "invalid" that was
previously used by the object that was destroyed. At any time in the
future, the computer is free to use that memory for any other purpose it
needs it for. In this simple case, it just happened that that memory was
still the same as when you called delete, so nothing bad happened when you
used it (illegally). But try it again sometime and you may have to reboot
your computer...or worse!

-Howard

Jul 22 '05 #5

P: n/a
Thanks a lot. It's clear for me now.

X

Howard wrote:
"xuatla" <xu****@gmail.com> wrote in message
news:40************@gmail.com...

One more question about new and delete:

I use new to create a CTest. And then delete it. But it seems that the
deletion is not successful. When I print it, it's still there.

Do I need to define new and delete for class by myself?

// main function
int main(void)
{
int N = 10;
CTest t1(N);
int i;

for ( i = 0; i < N; i++ ) t1[i] = i;

CTest *t2 = new CTest;

*t2 = t1;

for ( i = 0; i < N; i++ ) cout << (t1+*t2)[i] << endl;

delete t2;

for ( i = 0; i < N; i++ ) cout << (*t2)[i] << endl;
// still print out t2.

return 1;
}

Thanks a lot for your kind help!

X

Once you call delete on the pointer t2, it is illegal to use that pointer
(unless you assign it to another valid object first). What you are doing
*may* work in some cases (because it is *possible* that the memory at that
location has not changed...yet). But you can *never* rely on doing that
successfully. You are invoking "undefined behavior", which means that
anything can happen. It may work, it may crash, and it may even cause
*serious* problems! Simply put, "don't do that!" :-)

By the way, calling delete does not cause the computer to go to that memory
location and erase anything. What it does (well, one of the things it does,
somehow, behind the scenes), is mark the memory as "invalid" that was
previously used by the object that was destroyed. At any time in the
future, the computer is free to use that memory for any other purpose it
needs it for. In this simple case, it just happened that that memory was
still the same as when you called delete, so nothing bad happened when you
used it (illegally). But try it again sometime and you may have to reboot
your computer...or worse!

-Howard


Jul 22 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.