I'm reading the book "a complete guide to c++". I think there is a typo there on page 252. So I have three files as the following.
In file account.h,
// account.h
// Defining the class Account. class definition (methods prototypes) is usually put in the header file
// ---------------------------------------------------
#ifndef _ACCOUNT_ // if _ACCOUNT_ is not defined
#define _ACCOUNT_
#include <iostream>
#include <string>
using namespace std;
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
bool init( const string&, unsigned long, double);
void display();
};
#endif
// _ACCOUNT_
In file account.cpp,
// account.cpp
// Defines methods init() and display().
// ---------------------------------------------------
#include "account.h" // Class definition
#include <iostream>
#include <iomanip>
using namespace std;
// The method init() copies the given arguments
// into the private members of the class.
bool Account::init(const string& i_name,
unsigned long i_nr,
double i_balance)
{
if( i_name.size() < 1)
return false; // check data format to make sure it is valid
name = i_name;
nr = i_nr;
balance = i_balance;
return true;
}
// the method display() outputs private data.
void Account::display()
{
cout << fixed << setprecision(2)
<< "--------------------------------------\n"
<< "Account holder:" << name << '\n'
<< "Account number:" << nr << '\n'
<< "Account balance:" << balance << '\n'
<< "--------------------------------------\n"
<< endl;
}
And finally, in file account_t.cpp
// account_t.cpp
// Uses objects of class Account.
// ---------------------------------------------------
#include "account.h" // header file which contains class definition; (prototype for member functions)
int main()
{
Account current1, current2; // create two instances with name current1, current2
current1.init("Cheers, Mary", 1234567, -1200.99);
// have to call the init function to initialize a Account object; init function is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
current2 = current1;
current2.display();
current2.init("Jones, Tom", 3512347, 199.40);
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
I do not think it's correct; because obviously there is no way to get access the init member methods and the display member methods, right? I hope this is not a naive question.
EDIT: I tried to run the main function in file account_t.cpp, and got the following output.
~$ g++ account_t.cpp
/tmp/ccSWLo5v.o: In function `main':
account_t.cpp:(.text+0x8c): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0xb6): undefined reference to `Account::display()'
account_t.cpp:(.text+0xd5): undefined reference to `Account::display()'
account_t.cpp:(.text+0x132): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0x15c): undefined reference to `Account::display()'
account_t.cpp:(.text+0x176): undefined reference to `Account::display()'
collect2: error: ld returned 1 exit status
Any more comments are greatly appreciated.
There is no issue with what you are asking about. init and display are declared public in the definition of class Account and the file with the class definition is #includeed properly in the .cpp using these methods.
In order to use a function only its declaration is needed (which is in the class definition in the header which is included). The definition/implementation in the .cpp file is not needed to use the function.
Each .cpp is compiled individually (called a translation unit) and afterwards each use of a function (for which only the declaration might have been available) is linked to the correct definitions from the other translation units if necessary via the function's scope, name and signature. This is called the linking process.
An introductory book to C++ should explain how compilation and linking process work.
For g++, there is an easy way to compile all .cpp files individually as translation units and then directly link them together:
g++ account_t.cpp account.cpp
You always need to add all .cpp to the compiler invocation like that. (There are alternative ways, but this is the easiest one.)
However, as mentioned in the comments there are other issues with this program:
_ACCOUNT_ is a reserved identifier that one may not #define in a program. All identifiers starting with an underscore followed by a capital letter are reserved. Using them causes undefined behavior.
using namespace std; is bad, at the very least when used in a header file, see Why is "using namespace std;" considered bad practice?.
Classes have constructors. One should not write init methods in most cases. The constructor is responsible for constructing and initializing class instances. But no constructor is used in the code.
Money should never be stored in double, because arithmetic with double is imprecise. You should store the value in an integer type in dimensions of the smallest relevant unit of money (e.g. cents).
#include <iostream> is not needed in the header file. One should avoid adding #includes that are not needed.
init returns a boolean indicating successful initialization. But main never checks that value. If a function can fail with an error value, then you must check that error value returned by the function to make sure that continuing the rest of the program is safe.
Some of these points may be excusable as simplification for a beginner program, depending on how far the book got at this point (though 200+ pages should already cover a lot), but others aren't.
Example of constructor use doing the same thing:
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
Account(const string&, unsigned long, double);
void display();
};
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
}
int main()
{
Account current1("Cheers, Mary", 1234567, -1200.99);
// Create Account instance and initialize private members; constructor is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
Account current2 = current1; // Create second Account instance and copy private members from first one
current2.display();
current2 = Account("Jones, Tom", 3512347, 199.40); // Replace instance with a copy of a new one
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
The i_name.size() < 1 check (which is weirdly written, why not i_name.size() == 0?) would be realized by throwing an exception from the constructor:
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
if(i_name.size() == 0) {
throw invalid_argument("Account does not accept empty names!");
}
}
This requires #include<stdexcept> and is a more advanced topic.
So I'm trying to embed Lua into C++ and every time I try and compile I get this error:
/root/NetBeansProjects/test/main.cpp:20: undefined reference to `luaL_newstate'
/root/NetBeansProjects/test/main.cpp:31: undefined reference to `lua_settop'
/root/NetBeansProjects/test/main.cpp:35: undefined reference to `luaL_loadfilex'
/root/NetBeansProjects/test/main.cpp:35: undefined reference to `lua_pcallk'
/root/NetBeansProjects/test/main.cpp:38: undefined reference to `lua_close'
I've been searching for a solution for hours but I can't find anything helpful.
I installed Lua: apt-get install lua5.2 lua5.2-dev
Here's my code:
#include <cstdlib>
#include <iostream>
#include <string.h>
#include <string>
#include <lua5.2/lua.hpp>
using namespace std;
int main() {
// create new Lua state
lua_State *lua_state;
lua_state = luaL_newstate();
// load Lua libraries
static const luaL_Reg lualibs[] ={
{ "base", luaopen_base},
{ NULL, NULL}
};
const luaL_Reg *lib = lualibs;
for (; lib->func != NULL; lib++) {
lib->func(lua_state);
lua_settop(lua_state, 0);
}
// run the Lua script
luaL_dofile(lua_state, "test.lua");
// close the Lua state
lua_close(lua_state);
return 0;
}
What am I doing wrong?
First of all thanks for everyone's help on this.
As per my comment, the compiler will fail inside Netbeans unless the library is actually added to the project.
To rectify this inside Netbeans right click the project (left pane) -> Properties -> Build drop down -> Linker -> click three dots next to Libraries -> Add PkgConfig Library File -> Lua5.2
Your program should now compile correctly and life will be good.
I'm just starting to work on a project for class and I'm getting an error that I'm unsure how to fix. I'll do my best to provide all necessary details but if you need any more info please let me know. The project is to create a simple hash function and I'm getting a linker error when trying to compile. I will post all of my code as well as the error I receive when compiling. I have taken two previous programming classes but that was quite a while ago and I'm pretty out of practice at the moment so it may be an obvious mistake. Ignore all commented out code in hash.h because that is just function definitions that my teacher provided that I have not yet implemented. She also specifically requested that we put our hashing function in its own separate file. I should also specify that I'm using a Windows machine with cygwin64 to compile my code.
hash.h:
#ifndef __HASH_H
#define __HASH_H
#include <string>
#include <list>
using std::string;
using std::list;
class Hash {
public:
void remove(string); // remove key from hash table
//void print(); // print the entire hash table
void processFile(string); // open file and add keys to hash table
//bool search(string); // search for a key in the hash table
//void output(string); // print entire hash table to a file
//void printStats(); // print statistics
private:
// HASH_TABLE_SIZE should be defined using the -D option for g++
//list<string> hashTable [HASH_TABLE_SIZE];
list<string> hashTable [100];
int collisions;
int longestList;
double avgLength;
int hf(string); // the hash function
void insert(string);
// put additional variables/functions below
// do not change anything above!
};
#endif
hash.cpp:
#include "hash.h"
void Hash::remove(string string_to_remove)
{
int index = hf(string_to_remove);
for(list<string>::iterator iter = hashTable[index].begin(); iter != hashTable[index].end(); iter++)
{
if(*iter == string_to_remove)
hashTable[index].erase(iter);
}
}
void Hash::insert(string string_to_add)
{
int index = hf(string_to_add);
hashTable[index].push_back(string_to_add);
}
void Hash::processFile(string file_name)
{
insert(file_name);
}
hash_function.cpp
#include "hash.h"
int Hash::hf(string input)
{
int sum = 0;
for (int i = 0; i < 5; i++)
sum += (int)input[i];
cout << sum % 100 << endl;
return [sum % 100 /*HASH_TABLE_SIZE*/];
}
Compiler Error:
$ g++ hash_function.cpp testmain.cpp hash.cpp -o test
/tmp/cc42z5XM.o:hash.cpp:(.text+0x32): undefined reference to `Hash::hf(std::string)'
/tmp/cc42z5XM.o:hash.cpp:(.text+0x32): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Hash::hf(std::string)'
/tmp/cc42z5XM.o:hash.cpp:(.text+0x13c): undefined reference to `Hash::hf(std::string)'
/tmp/cc42z5XM.o:hash.cpp:(.text+0x13c): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Hash::hf(std::string)'
collect2: error: ld returned 1 exit status
I have a function, that when defined in the main file of my program, works as I wish, and produces a lot of undefined references, when defined in a header file.
This header file exists:
#include "Domain.h"
#include "Character.h"
class Item {
public:
Character input;
Item(Character c2);
};
Item pistol(int which, float strength);
The function that makes problems is pistol. It looks like
Item pistol(int which, float strength) {
Interval i = Interval(0, 1);
Domain d = Domain(i);
Character c = Character({d}, {1});
return Item(c);
}
When I try to link the code with my main program, all calls that refer to object in Domain.h and Character.h are undefined references, that means I get linking time errors like:
undefined reference to `Character::show()'
...
undefined reference to `Interval::Interval(float, float)'
...
these errors are at places in the code, which are not inside the pistol function.
When I move this function to my main program, everything works as expected:
#include "Domain.h"
#include "Character.h"
#include "Item.h"
Item pistol(int which, float strength) {
// definition, see above
}
int main() {
Item w2 = pistol(2, 0.5);
return 0;
}
What is the problem with that function being in Item.h/Item.cxx?
What do I need to do to put it their?
undefined reference is a linking stage error.
You most probably missed to link with a compilation unit, missed to recompile a dependent compilation unit, or tried to have a template class/function definition not seen by the compiler from all your compilation units using it!
I have tried to find a solution to my problem online, but I've been unsuccessful. I think my problem may be related to linking.
I have 3 files scanner.h , scanner.cpp and scanner_test.h I've trimmed the files as best I can.
scanner.h
class Scanner {
public:
Token *scan (const char *);
};
scanner.cpp
#include "scanner.h"
Token scan(const char *text){
// Do something code
}
scanner_test.h
#include "scanner.h"
Scanner *s ;
void test_setup_code ( ) {
s = new Scanner() ;
}
Token *tks = s->scan ( text ) ; //This line gives the error
The error when I try to compile and run is from scanner_test.h undefined reference to `Scanner::scan(char const*)
This is my understanding of the code:
scanner_test.h includes the scanner.h file which is linked to scanner.cpp during compilation and this file has the definition for Scanner::scan(char const*)
In scanner.cpp, you need:
Token* Scanner::scan(const char *text) { ... }
// ^^^^^^^^^
otherwise you are implementing a free function called scan, not the member method from Scanner. (Note I also added the * you were missing, but the compiler will tell you this anyways once you added the Scanner:: part)