Member Avatar for Taniotoshi

Hello everybody

I am doing a little code to learn a bit more about C++. Do not be amazed if you find that code useless, it is mainly just for me to improve. :) This is my first C++ program and I started few days ago... [/I]One class is used for "random number generation" purposes, and "Printer" would be used to print some infos. The output is 50 random numbers displayed one per line:

General information:
The value of system time (unsigned) is: 1235691452

Test of randomGenerator:
0 1
1 34
2 1
3 46
4 22
5 43
6 40
7 15
8 32
9 10
10 23
etc...

I have few problems:
One concerns is about my use of the Printable "interface". I am not familiar with this in C++.
Another one is I guess in my architecture; uncertainties about where to define variable_toString() method. Uncertainties about loads of things actually! :confused:
All of these unable me to print a RandomGenerator instance along with its internals.

Here is the code:

  • Printable.h

I use this one to define any class as "printable"; having a toString method.

#ifndef PRINTABLE_H
#define PRINTABLE_H

#include "Printer.h"

class  Printable {
	   
	protected: 
		virtual const std::string toString() = 0;	  		 
};

#endif
  • RandomGenerator.h
#ifndef RANDOM_GENERATOR_H
#define RANDOM_GENERATOR_H

#include "Printable.h"

/*
* This class defines a random generator used for different purposes in this program.
*/	
class RandomGenerator : public Printable {

	private:
		unsigned int lowest_number;
		unsigned int highest_number;
		unsigned int range;
		unsigned long seed;

	public:
		RandomGenerator(unsigned int _lowest_number, unsigned int _highest_number);		
		unsigned long generate_seed(unsigned int _coeff);
		unsigned int generate_rand();
		virtual const std::string toString();
		
}; // End of class

#endif
  • RandomGenerator.cpp
    including RandomGenerator.h uniquely.
    I skip the useless stuffs and give only toString() method implementation.
// Typecast "this" to string
const std::string RandomGenerator::toString() {
    
    Printer *rg_printer = NULL;
   	rg_printer = new Printer();
	std::stringstream sstream (stringstream::out);
	std::string object_to_string;
	
	sstream << "Random minima: " << rg_printer->variable_toString(lowest_number)
			<< "   Random maxima: " << rg_printer->variable_toString<unsigned int>(highest_number) 
			<< "   Current seed: " << rg_printer->variable_toString<unsigned long>(seed);
		   		   		   	   				   	 		   		   	 				  	   		  
	object_to_string = sstream.str();
	return object_to_string;
}

Yeah I know, this instanciation + use of Printer here looks definitely dodgy. I started by putting this function directly in RandomGeneration class, doing the same thing... and it was working! (Yeah!! that's enough for me to be happy! :cool: ) But obviously, if you have to redefine it everytime... That's why it is now in Printer class. But... not working!
I got this kind of Linker errors:

[Linker error] undefined reference to `std::string Printer::variable_toString<unsigned long>(unsigned long)' 
[Linker error] undefined reference to `std::string Printer::variable_toString<unsigned int>(unsigned int)' 
[Linker error] undefined reference to `std::string Printer::variable_toString<unsigned int>(unsigned int)'

Related to the three numbers I am putting into the stringstream, or I should rather say, to the three calls of variable_toString() method:

  • Printer.h
#ifndef PRINTER_H
#define PRINTER_H

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

// Would be used to print/retrieve info
class Printer {

	private:

	public:
		Printer();
		void print_blank_line();
		void print_string(std::string _string_to_print);
		template<typename Variable>
		std::string variable_toString(Variable _variable);

};

#endif
  • Printer.cpp
    including Printer.h only.
    I skip the useless stuffs and give only variable_toString() method implementation.
// Typecast a variable to string
template<typename Variable>
string Printer::variable_toString(Variable _variable) {
	
	stringstream sstream (stringstream::out);
	string variable_to_string;
	
	sstream << _variable;	   		   	 				  	   		  
	variable_to_string = sstream.str();
 	
	return variable_to_string;
}

And finally the main (sorry for this big amount of code):

//#include "stdafx.h"
#include "RandomGenerator.h"
#include "Printer.h"
using namespace std;

#define ARRAYSIZE(x)  (sizeof(x)/sizeof(*(x)))

int main (int argc, char *argv[]) {	

	RandomGenerator *random_1_50 = NULL;
	Printer *m_printer = NULL;	
	int chromosome[50]; 
	int i;

	m_printer  = new Printer();
	random_1_50 = new RandomGenerator(1, 50);
	for (i = 0; i < ARRAYSIZE(chromosome); i++)
		chromosome[i] = 0;

	m_printer->print_string("General information: ");	
	// Output system time used to seed random generator
	cout << "The value of system time (unsigned) is: " << (unsigned) time(0) << endl;		
	m_printer->print_blank_line();
  
    m_printer->print_string("Test of randomGenerator: ");
	m_printer->print_string(random_1_50->toString());


	srand(random_1_50->generate_seed(1));

	for (i = 0; i < ARRAYSIZE(chromosome); i++) {
		chromosome[i] = random_1_50->generate_rand();
		cout << i << " " << chromosome[i] << endl;
	}

	m_printer->print_blank_line();

    system("PAUSE");
	return EXIT_SUCCESS;    

} // End of main

This is obviously a bad design or rather weird anyway.
Why do I get these errors?
What about my use of the interface?
What about my use of the template? Why do I have to define it both in Printer .h and .cpp?
What about the way I include file? I tried to include a minimum; so that I can learn about "who is coming from where?". In Printable I call a bunch of headers which are used only in Printer. The idea was to be able to create any printable class by just implementing Printable and including Printer.h. Is it a bad choice? What is the real way to do it?
Other point: I saw there are easier way to do what I want, overloading a function based on iostreams, stuffs like that. But I would like to get this "way" working first if possible. I do not like being in these situations of uncertainties. I am to the point where I stare at my computer for hours, seeing nothing wrong but still having this "it_must_be_coming_from_me"-ish attitude! :confused:

But still, could be a story of compiler no? I use Dev-C++ with apparently g++ compiler.(That is what is written in the compiler log).

I think I am going to stop here for now. I can hear everybody saying: "Finally!!", and I apologize for any inconvenience this post could have caused to any of you! :D

Still any advices, hints, links, examples - even greetings - are welcomed!

cheers

Recommended Answers

All 8 Replies

>Yeah I know, this instanciation + use of Printer here looks definitely dodgy.
You are using dynamic memory management using new. Be sure to free the memory with delete.
>Why do I get these errors?
These are the Linking error you are getting.
Its probable that you are not including the implementation file of your header file while linking.
use this if you are on g++

g++ -o final.exe main.cpp RandomGenerator.cpp Printer.cpp

>What about the way I include file?
Generally, you write a header file(declarations) and a implementation .cpp file(definitions). Then what you usually do is, you compile the .cpp files of all the header file separately(in your case you need to compile RandomGenerator.cpp and Printer.cpp separately).Remember I said ONLY COMPILE, which can be done by the -c flag like this:

g++ -c -o RandomGenerator.o RandomGenerator.cpp
g++ -c -o Printer.o Printer.cpp

and you get two binary .o files. You can distribute the .h file and these .o files to anyone who purchases your class.(and you can also keep it open-source by giving the person the .cpp file too)
Pre-compiling helps in two ways:
1.It make your code encrypted hence it is hard to get the original source by reverse engineering it. Thus you dont need to give anyone your full source.
2.It saves the time in compiling those .cpp file since they are already compiled now.
Hence you should, after compiling those .o files, have to link while compiling your main.cpp like this

g++ -o final.exe main.cpp Printer.o RandomGenerator.o

and you're done.

Another point is that you are messing yourself in header files. I mean look at this:
In main you include Printer.h and RandomGenerator.h
RandomGenerator.h include printable.h which in turn includes Printer.h.
Although, your code will compile, but it is dirty.
You should have done probably like this:
Printable being your base class, you should not include Printer.h in that.
Instead, include Printable.h in all those classes' header file which are derived from Printable(the RandomGenerator) .
Now just include the Printer.h and RandomGenerator.h in your main program.

Some few more points:
Dont use macros as you used(#define ARRAYSIZE(x)), use inline function instead.
Dont use system("PAUSE"); , use cin.get() instead.

Member Avatar for Taniotoshi

Hello again
thanks for your help man, but I guess I am not getting it right. I tried your approach. I understood I have to run the "lines" you gave me when in my project folder. But for some obscure reasons, I do not manage to access the concerned partition (cd E:\ not working !?) I am not use with terminal commands when working under Windows...
So I tried to do it "semi-manually" via the IDE.
What I have tried:

  • I first removed all the .o files in my project folder (object files right?)
  • I then compiled only Randomgenerator.cpp
    Compiler: Default compiler
    Compiling RandomGenerator.cpp
    Done.
  • The same with Printer.cpp
    Compiler: Default compiler
    Compiling Printer.cpp
    Done.
  • I finally compiled the project but still get the same linker errors.

I then tried something else. I commented the function toString() contents in RandomGenerator. And did the same as above.

Compiler: Default compiler
Compiling main.cpp
Compiling stdafx.cpp
Linking BinPacking.exe
Done.

The linking now is working... I am not sure to understand what is happening here...

I guess I cannot say it is coming from the compiler/linker anymore, right? I feel a bit lost... :(

You should have done probably like this:
Printable being your base class, you should not include Printer.h in that.
Instead, include Printable.h in all those classes' header file which are derived from Printable(the RandomGenerator) .
Now just include the Printer.h and RandomGenerator.h in your main program.

I tried this in the first place. But as Printer and Printable are closely related (variable_toString and toString methods), I still had to also include a <string> and <sstream> in RandomGenerator and Printer. Also <string> in Printable. That is why I thought about doing it this way. Including "Printer.h" in Printable allows me to only include Printable in any class I want to define a toString method to... I do not have to worry about anything else. Is it really nasty? What would be a nice compromise?

What is wrong with my use of MACRO?
I changed the "System" function. When I look at the name, I guess it is a matter a compatibility or rather protability to other systems right?
Is there any way to use a function coming from another class (variable_toString) without instantiating this class? I feel bad about creating an instance of Printer in RandomGenerator... :-/

Thank you in advance guys!
cheers

>What is wrong with my use of MACRO?
Read this(Marshal Cline FAQs) http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5 about why macros are evil.
>I changed the "System" function. When I look at the name, I guess it is a matter a >compatibility or rather protability to other systems right?
Yes.
>Is there any way to use a function coming from another class >(variable_toString) without instantiating this class? I feel bad about creating an >instance of Printer in RandomGenerator...
Yes, Declare the function as static to the class. And then you can call it as Printer::variable_toString(Variable _variable) Now regarding your project, I would suggest you should zip it up and upload it here as I cannot likely say from where the problem is coming without seeing the code.

Member Avatar for Taniotoshi

Thanks for your time. I attached the code.

Read this(Marshal Cline FAQs) http://www.parashift.com/c++-faq-lit...s.html#faq-9.5 about why macros are evil.

Thanks for the link, gonna have a look soon.

Yes, Declare the function as static to the class. And then you can call it as Printer::variable_toString(Variable _variable)

Done and working in the version I attached.

You will see that I also changed the way I include files; Printer.h is not included anymore in Printable. But i am sure there is a better solution than the one i have used. All the files are in the same folder... Definitely ugly! I am used xith packages in java, but not really suer about how things are supposed to be organised in C++...

Thanks for everything again.

Member Avatar for Taniotoshi

??
Any help still welcomed...

Ok, I have seen your project and have come to the following conclusion:
You are using template function right? Which is making trouble here. How? Well here is a brief explanation:
The compiler does not generate the template code just as soon as it sees the definition. It will only generate the code when it sees a function call. Now what happens is, when your Printer.cpp get compile, no code regarding the templated function gets generated. So now, when you link your executable(after compiling all the source file to object file), the linker complaints that it do not have the definition of the function. And hence you get errors.
What is the solution?
The simplest solution in your case is to define all the templated function in the header file(Printer.h) itself.
Other solution exists, but they are complex and non-portable.

So, just define all your templated function in the header file so that the calling code and the definition lies in the same object file.

Thats all !!:yawn:

Member Avatar for Taniotoshi

Working like a charm! Thanks a lot for your time! I sure need to read more to spot particularities like that. Bu there are so many stuffs to read!! Which is in fact a good thing; you do not get bored! I am impressed by your "altruism"; and it looks like something common on DaniWeb. That truly is amazing; Thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.