I'm doing some auxiliary projects to make sure I'm understanding things as I go. I tried to define a complex number class as well as the * operator on complex numbers. I did this in one file, and everything worked fine. Then I tried to break it up into 3 files: a header file defining the complex class, a source file that defines complex multiplication, and a main file where I simply use these things to multiply two complex numbers. This is where I run into trouble. I have a member function init() in the complex class which sets the number equal to (0,0). I think the problem is trying to define that. Here are all three files (they're short) as well as the compiler log. Thanks in advance.
Chris
Complex1.h
ifndef COMPLEX1_H
define COMPLEX1_H
class complex {
public:
float Re;
float Im;
void init();
In file included from Complex1.cpp:3:
C:/Dev-Cpp/include/Complex1.h:13: error: declaration of void complex::init()' outside of class is not definition
Complex1.cpp: In functioncomplex& operator*(complex&, complex&)':
Complex1.cpp:14: warning: reference to local variable `w' returned
make.exe: *** [Complex1.o] Error 1
Execution terminated
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
from Complex1.h, or replace it with the definition in Complex1.cpp (and remove that definition). Or better yet place the body in the class definition thus:
which is implicitly inline. You would then need to remove all other definitions and declarations.
The inline qualifier cannot work unless the definition appears in the same compilation unit as the usage, and for that to happen when you have multiple compilation units, the definition must be placed in the header. In practice inline is only a hint to the compiler, and unless you switch on optimisation, GCC ignores it in all cases, and just generates copies of the function in each compilation unit that are called in the normal way.
Rather than use an init() function, it usually makes more sense to use a constructor, and in this case you can use an initializer list which is more efficient than member assignment:
With that definition, all instantiations will either be initialised with 0,0 or with arguments passed to the constructor. So your main() would look like this:
int main()
{
complex z1(1, 2) ;
complex z2(3, 4) ;
complex w = z1 * z2 ;
system("PAUSE");
return EXIT_SUCCESS;
}
Moreover, it would make sense to have a constructor that takes a complex initilaiser:
Note that the second operator() is the same as your init() function except instead of invoking:
w->init() ;
you can merely write:
w() ;
I am not sure of the wisdom of this second implementation, since using the first and writing;
w( 0, 0 ) ;
is probably far clearer. You could even define:
complex::operator()( float r = 0, float i = 0) { Re=r; Im=r; }
and use either w() or w(0,0) with just the one definition.
For ultimate flexibility, you might define complex as a class template so that it can be instantiated for other types such as double, long double and int for example without writing and maintaining special versions for each type.
And of course much much more!
Now all that said, you are aware are you that the C++ standard library includes a std::complex template class? http://www.dinkumware.com/manuals/?manual=compleat&page=complex.html. Even if you want to create your own as an academic exercise, you might consider using that as a model of good C++ design.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There doesn't seem to be a problem with using #include <Complex1.h>. I created a folder where I am putting all of my practice header files, and I added that to the places where the compiler looks for header files.
"Is there any special reason you put your constructor and operator declarations outside the scope of the class?" Perhaps this was a really bad example, but I know that a class might have some rather complicated member function. I understand that one should not define functions in header files. So I wanted to see how to have a header file defining a class, where the member functions were defined in another source file.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
> first of all, #include <Complex1.h> should be #include "Complex1.h"
Not at all. The error log does not indicate that the compiler failed to find <complex1.h>. You have to base your assertions on the facts before you, otherwise you will merely confuse people with erroneous and irrelevant advice.
If he put it in say "C:/Dev-Cpp/joshi" which has been defined as an include path via a -I<path> argument, then <Complex1.h> is entirely correct. Given that that was my advice in response to an earlier question, I suspect that that is what he has done.
> Is there any special reason you put your constructor and
> operator declarations outside the scope of the class?
1) He did not define a constructor. You cannot define a constructor outside of the scope of a class - what would it construct!?. His complex::init() was defined outside of the class definition, but not outside its scope. It was declared in the class definition, and by way of the complex:: scope resolution was still defined in the scope of the class.
2) A binary operator may be defined by either a member function taking one argument or a non-member function taking two. It is largely a matter of preference, but IMO the latter is more intuitive. He is in good company; in Bjarne Stroutrup's "The C++ Programming Language", an example of operator overloading using a complex class is presented with operator+() defined as a non-member function. In fact he recommends, defining += as a member, and then + as a non-member defined in terms of += (and so it follows to define = as a member and then * in terms of =). This reduces code maintenance and ensures that say x = x * y is exactly equivalent to z *= y.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks Clifford. By the way, I really appreciate all of your help. I wish I could return the favor. I'm finishing my PhD in math this year. On the off chance that you ever have a math question you'd like to discuss, feel free to email me at hammondc1 at gmail.com.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm using DEvC++4.9.9.2 on Windows XP.
I'm doing some auxiliary projects to make sure I'm understanding things as I go. I tried to define a complex number class as well as the * operator on complex numbers. I did this in one file, and everything worked fine. Then I tried to break it up into 3 files: a header file defining the complex class, a source file that defines complex multiplication, and a main file where I simply use these things to multiply two complex numbers. This is where I run into trouble. I have a member function init() in the complex class which sets the number equal to (0,0). I think the problem is trying to define that. Here are all three files (they're short) as well as the compiler log. Thanks in advance.
Chris
Complex1.h
ifndef COMPLEX1_H
define COMPLEX1_H
class complex {
public:
float Re;
float Im;
void init();
};
inline void complex::init();
complex& operator * ( complex& w1, complex& w2);
endif
Complex1.cpp
include <cstdlib>
include <cmath>
include <Complex1.h>
using namespace std;
inline void complex::init() //Constructor for a complex number
{
Re=0;
Im=0;
}
complex& operator * ( complex& w1, complex& w2) // We multiply two complex numbers
{
complex w;
w.Re=w1.Rew2.Re-w1.Imw2.Im;
w.Im=w1.Rew2.Im+w2.Rew1.Im;
return w;
}
ComplexNumMain2.cpp
include <cstdlib>
include <iostream>
include<cmath>
include<Complex1.h>
using namespace std;
int main(int argc, char *argv[])
{
complex z1;
complex z2;
complex w;
z1.Re=1;
z1.Im=2;
z2.Re=3;
z2.Im=4;
w=z1*z2;
}
Compiler Log
Compiler: Default compiler
Building Makefile: "C:\Dev-Cpp\Getting Started\ComplexNumbers2\Makefile.win"
Executing make...
make.exe -f "C:\Dev-Cpp\Getting Started\ComplexNumbers2\Makefile.win" all
g++.exe -c Complex1.cpp -o Complex1.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -I"C:/Dev-Cpp/joshi"
In file included from Complex1.cpp:3:
C:/Dev-Cpp/include/Complex1.h:13: error: declaration of
void complex::init()' outside of class is not definition Complex1.cpp: In function
complex& operator*(complex&, complex&)':Complex1.cpp:14: warning: reference to local variable `w' returned
make.exe: *** [Complex1.o] Error 1
Execution terminated
The operator() definitions earlier should have been declared void:
void operator()( float r, float i) { Re=r; Im=r; }
void operator()() { Re=0; Im=0; }
Sorry.
first of all, #include <Complex1.h> should be #include "Complex1.h"
Is there any special reason you put your constructor and operator declarations outside the scope of the class?
Dick
Remove this line:
inline void complex::init();
from Complex1.h, or replace it with the definition in Complex1.cpp (and remove that definition). Or better yet place the body in the class definition thus:
class complex {
public:
float Re;
float Im;
void init(){ Re=0; Im=0; }
} ;
which is implicitly inline. You would then need to remove all other definitions and declarations.
The inline qualifier cannot work unless the definition appears in the same compilation unit as the usage, and for that to happen when you have multiple compilation units, the definition must be placed in the header. In practice inline is only a hint to the compiler, and unless you switch on optimisation, GCC ignores it in all cases, and just generates copies of the function in each compilation unit that are called in the normal way.
Rather than use an init() function, it usually makes more sense to use a constructor, and in this case you can use an initializer list which is more efficient than member assignment:
class complex {
public:
complex() : Re(0), Im(0) {}
complex( float r, float i) : Re(r), Im(i) {}
float Re;
float Im;
} ;
With that definition, all instantiations will either be initialised with 0,0 or with arguments passed to the constructor. So your main() would look like this:
int main()
{
complex z1(1, 2) ;
complex z2(3, 4) ;
complex w = z1 * z2 ;
system("PAUSE");
return EXIT_SUCCESS;
}
Moreover, it would make sense to have a constructor that takes a complex initilaiser:
class complex {
public:
complex() : Re(0), Im(0) {}
complex( float r, float i) : Re(r), Im(i) {}
complex( complex i) : Re(i.Re), Im(i.Im) {}
float Re;
float Im;
} ;
Then you can write:
complex z1(1, 2) ;
complex z2(3, 4) ;
complex w( z1 * z2 ) ;
Further, if you do need to re-initilaise a complex object after it is instantiated you can define a functor thus:
class complex {
public:
complex() : Re(0), Im(0) {}
complex( float r, float i) : Re(r), Im(i) {}
complex( complex i) : Re(i.Re), Im(i.Im) {}
operator()( float r, float i) { Re=r; Im=r; }
operator()() { Re=0; Im=0; }
float Re;
float Im;
} ;
Note that the second operator() is the same as your init() function except instead of invoking:
w->init() ;
you can merely write:
w() ;
I am not sure of the wisdom of this second implementation, since using the first and writing;
w( 0, 0 ) ;
is probably far clearer. You could even define:
complex::operator()( float r = 0, float i = 0) { Re=r; Im=r; }
and use either w() or w(0,0) with just the one definition.
For ultimate flexibility, you might define complex as a class template so that it can be instantiated for other types such as double, long double and int for example without writing and maintaining special versions for each type.
And of course much much more!
Now all that said, you are aware are you that the C++ standard library includes a std::complex template class? http://www.dinkumware.com/manuals/?manual=compleat&page=complex.html. Even if you want to create your own as an academic exercise, you might consider using that as a model of good C++ design.
Clifford
There doesn't seem to be a problem with using #include <Complex1.h>. I created a folder where I am putting all of my practice header files, and I added that to the places where the compiler looks for header files.
"Is there any special reason you put your constructor and operator declarations outside the scope of the class?" Perhaps this was a really bad example, but I know that a class might have some rather complicated member function. I understand that one should not define functions in header files. So I wanted to see how to have a header file defining a class, where the member functions were defined in another source file.
You were doing fine, I think that response did more to confuse than clarify.
> first of all, #include <Complex1.h> should be #include "Complex1.h"
Not at all. The error log does not indicate that the compiler failed to find <complex1.h>. You have to base your assertions on the facts before you, otherwise you will merely confuse people with erroneous and irrelevant advice.
If he put it in say "C:/Dev-Cpp/joshi" which has been defined as an include path via a -I<path> argument, then <Complex1.h> is entirely correct. Given that that was my advice in response to an earlier question, I suspect that that is what he has done.
> Is there any special reason you put your constructor and
> operator declarations outside the scope of the class?
1) He did not define a constructor. You cannot define a constructor outside of the scope of a class - what would it construct!?. His complex::init() was defined outside of the class definition, but not outside its scope. It was declared in the class definition, and by way of the complex:: scope resolution was still defined in the scope of the class.
2) A binary operator may be defined by either a member function taking one argument or a non-member function taking two. It is largely a matter of preference, but IMO the latter is more intuitive. He is in good company; in Bjarne Stroutrup's "The C++ Programming Language", an example of operator overloading using a complex class is presented with operator+() defined as a non-member function. In fact he recommends, defining += as a member, and then + as a non-member defined in terms of += (and so it follows to define = as a member and then * in terms of =). This reduces code maintenance and ensures that say x = x * y is exactly equivalent to z *= y.
Clifford
Thanks Clifford. By the way, I really appreciate all of your help. I wish I could return the favor. I'm finishing my PhD in math this year. On the off chance that you ever have a math question you'd like to discuss, feel free to email me at hammondc1 at gmail.com.