PDA

View Full Version : Problem with simple C++ code




papermonkey11
Apr 20, 2012, 07:11 PM
Hello everyone! I have been writing Java for quite some time now and I though I'd try C++. So I have a problem I can't quite figure out.

The code I tried to write is simply calling a function from another class (located in another file) to print a simple message. The following is the code:

The main class file
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>

#include "Printer.h"

using namespace std;

//inline void keep_window_open() {char ch; cin>>ch;}

int main(){

Printer printer;
printer.actualPrint();

return 0;
}

The "class the function is in"'s header file (Printer.h):

#include <iostream>

using namespace std;

class Printer{

public:

//Declaration of the printing function
void actualPrint();
};

The second class (Printer.cc):

#include "Printer.h"

void Printer::actualPrint(){
std::cout<<"Hooray!! Printing from another class!!!\n";
}

This code runs perfectly fine on Windows (using Microsoft Visual C++ 2010 Express) but on my Mac i get the following error:

Undefined symbols:
"Printer::actualPrint()", referenced from:
_main in ccnldy3J.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Now the akward part. On my Mac if I change the following line in the main file

#include "Printer.h"

to

#include "Printer.cc"

everything runs smoothly (on Windows it did not compile, as I expected). The thing is everywhere I looked I'm supposed to include the header file in the main class not the .cc file (Changing the extension was just sheer coincidence). I'm pretty sure including the .cc is the wrong way to go.


Any help on why this is happening would be greatly appreciated.

Edit: Code compiled with g++

Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5666.3~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)



chown33
Apr 20, 2012, 07:46 PM
How are you compiling the source code? Are you using Xcode? The Terminal command-line? A makefile?

You wrote "Code compiled with g++", but Xcode is capable of compiling with g++, so it doesn't answer the question.

If you're using a Terminal command-line, please post the exact command(s) used to compile.

Basically, if Printer.cc and main.cc (or whatever you called it) are in separate files, then you need to compile them individually to produce .o files. You then "compile" the .o files to produce a single executable (I put "compile" in quotes because it's really only linking the .o files together, even though the command is still the g++ compiler, not a separate linker program).

Completely fabricated example:
g++ -c Printer.cc
g++ -c main.cc
g++ Printer.o main.o -o runme
./runme

papermonkey11
Apr 20, 2012, 08:17 PM
Hi! Thank you for the swift response.

Compiling/linking is done though the Terminal with a single command.

g++ main.cc -o Object

and then

./Object

I also have to thank you because your way of individually compiling and THEN linking worked like a charm!

Would I be asking too much of you, if I asked if you knew the reason for the need to individually compile and then link?

Thanks again. :)

chown33
Apr 20, 2012, 09:12 PM
There isn't a need to individually compile. You can compile and link both source files in one command line:
g++ main.cc Printer.cc -o runme
./runme

But since you have two separate source files (main.cc and Printer.cc), you must compile them both (at some point), and also tell the linker that they're both needed to produce the single executable. You can do that with one command-line or with several, but it must still be done.

The larger issue is how scalable the single command-line is. After about a half-dozen source files, it begins to take a noticeable amount of time to recompile every file every time. That's why there are separately linkable files in the first place: to avoid having to recompile every file every time. This is also why there are things like makefiles (http://en.wikipedia.org/wiki/Make_(software)), that list the dependencies between headers and source: to know when to recompile and when not to.

The simple-minded approach is to recompile every file when any file changes. This scales poorly, though, hence the desire to only recompile the minimum set of files that encompass the changes since the last build.

You might not be aware that an IDE (such as Xcode or Visual C++) is only recompiling some files, and not recompiling others. Most IDEs are designed to hide this from you, because it's only a build-level detail. But since you're now compiling at the command-line, you have to be aware of all these build-level details.

If you want to remain blissfully unaware of such details, you should use an IDE (such as Xcode), or learn to use a build system (http://en.wikipedia.org/wiki/Build_automation) like make, maven (http://en.wikipedia.org/wiki/Apache_Maven), ant (http://en.wikipedia.org/wiki/Apache_Ant), or countless others (http://en.wikipedia.org/wiki/List_of_build_automation_software) whose names I don't even recall.


If you have g++ installed, you probably also have make installed, so that would be a simple place to start. Not that make is all that simple (the O'Reilly book is good), but at least you won't have to install (or build) another build-system to get started.

And there's a certain simplicity and clarity in makefiles, at least for simple multi-file projects. Things really only get hairy when there's many files in many sub-dirs, or a wide variety of build options (like conditional compilation for multi-platform targets).

The classic test for make's presence is this command:
make love

If it says "not war?" you have a classic make. If it says there's no rule to make target love, you have plain old mundane make. Either will work.

papermonkey11
Apr 21, 2012, 07:21 AM
Thanks again for all the useful information.

I'll look into make as it sounds exactly like what I need.