unresolved external link2019 confusion - c++

I'm trying to resolve an unresolved external (link2019 error). There are many posts on StackOverflow about this issue, but either I am not understanding the error or I am blind to it.
The error is caused by my generate_maze function (specifically by the rand_neighbor() call, right?) but my understanding is that these are all "resolved".
I truncated the code a little bit because it is quite verbose. I hope this was appropriate.
void generate_maze (Vector<int> &coords, Grid<bool> &included, Maze &m);
int main() {
Grid<bool> included = initialize_grid();
Vector <int> coords = rand_coords();
Vector <int> current_point = coords;
generate_maze(coords, included, m);
return 0;
}
void generate_maze (Vector<int> &coords, Grid<bool> &included, Maze &m) {
while (gridIsTrue == false) {
Vector<int> neighbor = rand_neighbor(coords, included);
pointT neighborpoint = {neighbor[0], neighbor[1]};
pointT current_point = {coords[0], coords[1]};
if (included.get(neighbor[0], neighbor[1]) == false) {m.setWall(current_point, neighborpoint, false); included.set(neighbor[0], neighbor[1], true); current_point = neighborpoint;}
}
}
Vector<int> rand_neighbor(Vector<int> &coords, Grid<bool> &included) {
while (1) {
int randomint;
randomint = randomInteger(1,4);
if (randomint == 1) {if (included.inBounds(coords[0], coords[1]+1)) {coords[1] = coords[1]+1; break;}}
if (randomint == 2) {if (included.inBounds(coords[0], coords[1]-1)){coords[1] = coords[1] -1; break;}}
if (randomint == 3) {if (included.inBounds(coords[0] -1, coords[1])){coords[0] = coords[0] -1; break;}}
if (randomint == 4) {if (included.inBounds(coords[0] +1, coords[1])){coords[0] = coords[0] + 1; break;}}
}
return coords;
Error:
error LNK2019: unresolved external symbol "class Vector<int> __cdecl rand_neighbor(class Vector<int>,class Grid<bool> &)" (?rand_neighbor##YA?AV?$Vector#H##V1#AAV?$Grid#_N###Z) referenced in function "void __cdecl generate_maze(class Vector<int> &,class Grid<bool> &,class Maze &)" (?generate_maze##YAXAAV?$Vector#H##AAV?$Grid#_N##AAVMaze###Z)
1>C:\Users\com-user\Desktop\New folder\maze\assign3-maze-PC\Maze\Debug\Maze.exe : fatal error LNK1120: 1 unresolved externals

Using the nice web c++ demangler here you can see that your undefined reference ?rand_neighbor##YA?AV?$Vector#H##V1#AAV?$Grid#_N###Z actually means class Vector __cdecl rand_neighbor(class Vector,class Grid &). The parameters are missing from your error message.
Now, do you see the difference between the declaration and the definition of your function?
class Vector __cdelc rand_neighbor(class Vector,class Grid &);
Vector<int> rand_neighbor(Vector<int> &coords, Grid<bool> &included) { /* ... */}
Let me normalize them a bit:
Vector<int> rand_neighbor(Vector<int>, Grid<bool> &);
Vector<int> rand_neighbor(Vector<int> &, Grid<bool> &) { /* ... */}
You forgot a reference (&) in the prototype of the function! Thus, your definition is of a different function.

As the linker is telling you, the problem is with the rand_neighbor() function. You provided a declaration for it (if you didn't you would get a compiler error rather than a linker error), but you haven't provided a definition.

Related

Error Code LNK2019 & LNK1120 [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
I create this file over and over and cant seem to see why I'm getting this error. I tried going to the line where the code is but the format seem correct I may just need another set of eyes .
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void readString(char*, int);
void changeToUppercase(char*, int);
void displayStringInUppercase(char*, int);
int main()
{
int arraySize;
char* characterArray;
cout << "Enter the size of dynamic array: ";
cin >> arraySize;
characterArray = new char[arraySize];
readString(characterArray, arraySize);
changeToUppercase(characterArray, arraySize);
displayStringInUppercase(characterArray, arraySize);
delete [] characterArray;
system ("pause");
return 0;
}
void changeToUppercase(char* characterArray, int arraySize)
{
for(int i = 0; i < arraySize; i++)
characterArray[i] = toupper(characterArray[i]);
}
void displayStringInUppercase(char* characterArray, int arraySize)
{
cout << "\nThestring inupper case letters: ";
for(int i = 0; i < arraySize; i++)
characterArray[i] = toupper(characterArray[i]);
}
This is the error codes that keep popping up:
error LNK2019: unresolved external symbol "void __cdecl readString(char *,int)" (?readString##YAXPADH#Z) referenced in function _main
fatal error LNK1120: 1 unresolved externals
You use a forward declaration: void readString(char*, int); but then never actually define this function.
Define your readString function later in your code like...
void readString(char* str, int a)
{
// do stuff
}
You are missing the readString function. You have a forward declaration that satisfies the compiler here
void readString(char*, int);
But no actual implementation of the function to satisfy the linker when it tries to put your program together. You need something along the lines of
void readString(char* characterArray, int arraySize)
{
// do stuff here
}

__thiscall already defined in .obj

I am getting linker errors which I cannot seem to find the root cause of, having checked for including .cpp files and reading other forums.
The errors are:
1>------ Build started: Project: Penguin_RPG, Configuration: Debug Win32 ------
1> main.cpp
1>c:\users\adam\documents\visual studio 2013\projects\penguin_rpg\penguin_rpg\dialogue.hpp(53): warning C4018: '<=' : signed/unsigned mismatch
1>c:\users\adam\documents\visual studio 2013\projects\penguin_rpg\penguin_rpg\main.cpp(39): warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>main.obj : error LNK2005: "public: __thiscall Area::Area(class Dialogue,class Inventory,class std::vector<class Creature *,class std::allocator<class Creature *> >)" (??0Area##QAE#VDialogue##VInventory##V?$vector#PAVCreature##V?$allocator#PAVCreature###std###std###Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Creature::Creature(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,int,int,int,double,unsigned int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Creature##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##HHHHNI0#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Creature::Creature(void)" (??0Creature##QAE#XZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Dialogue::Dialogue(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >)" (??0Dialogue##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##V?$vector#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##V?$allocator#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###2##2##Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Item::Item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Item##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##0#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Weapon::Weapon(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int,double)" (??0Weapon##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##0IN#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Dialogue::activate(void)" (?activate#Dialogue##QAEHXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_armour(class Armour *,int)" (?add_armour#Inventory##QAEXPAVArmour##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_item(class Item *,int)" (?add_item#Inventory##QAEXPAVItem##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_weapon(class Weapon *,int)" (?add_weapon#Inventory##QAEXPAVWeapon##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::clear(void)" (?clear#Inventory##QAEXXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Creature::equipArmour(class Armour *)" (?equipArmour#Creature##QAEXPAVArmour###Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Creature::equipWeapon(class Weapon *)" (?equipWeapon#Creature##QAEXPAVWeapon###Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: unsigned int __thiscall Creature::expToLevel(unsigned int)" (?expToLevel#Creature##QAEII#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: bool __thiscall Creature::levelUp(void)" (?levelUp#Creature##QAE_NXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::merge(class Inventory *)" (?merge#Inventory##QAEXPAV1##Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::print(bool)" (?print#Inventory##QAEX_N#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_armours(bool)" (?print_armours#Inventory##QAEH_N#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_items(bool)" (?print_items#Inventory##QAEH_N#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_weapons(bool)" (?print_weapons#Inventory##QAEH_N#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_armour(class Armour *,int)" (?remove_armour#Inventory##QAEXPAVArmour##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_item(class Item *,int)" (?remove_item#Inventory##QAEXPAVItem##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_weapon(class Weapon *,int)" (?remove_weapon#Inventory##QAEXPAVWeapon##H#Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Area::search(class Creature &)" (?search#Area##QAEXAAVCreature###Z) already defined in atlas.obj
1>C:\Users\Adam\Documents\Visual Studio 2013\Projects\Penguin_RPG\Debug\Penguin_RPG.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
atlas.hpp:
#pragma once
#ifndef ATLAS_HPP
#define ATLAS_HPP
#include <vector>
#include "creature.hpp"
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include "area.hpp"
//atlas building functions. Atlases contain vectors of
//game data that is not modified. Could be replaced with
//functions that read from config files.
void buildatlas_creature(std::vector<Creature>& atlas);
void buildatlas_item(std::vector<Item>& atlas);
void buildatlas_weapon(std::vector<Weapon>& atlas);
void buildatlas_armours(std::vector<Armour>& atlas);
void buildatlas_area(std::vector<Area>& atlas,
std::vector<Item>& items, std::vector<Weapon>& weapons,
std::vector<Armour>& armours, std::vector<Creature>& creatures);
#endif //ATLAS_HPP
atlas.cpp:
#include "atlas.hpp"
void buildatlas_creature(std::vector<Creature>& atlas)
{
//fill the atlas
//Creature(name, health, str, end, dex, hitRate, level)
atlas.push_back(Creature("Rat", 8, 8, 8, 12, 2.0, 1));
return;
}
void buildatlas_item(std::vector<Item>& atlas)
{
//Item(name, description)
atlas.push_back(Item("Gold Coin",
"A small disc made of lustrous metal"));
atlas.push_back(Item("Iron Key",
"A heavy iron key with a simple cut"));
return;
}
void buildatlas_weapon(std::vector<Weapon>& atlas)
{
//Weapon(name, description, damage, hitRate)
atlas.push_back(Weapon("Iron Dagger",
"A short blade made of iron with a leather hilt",
5, 10.0));
atlas.push_back(Weapon("Excalibur",
"The legendary blade, bestowed upon you by the lady of the lake",
35, 35.0));
return;
}
void buildatlas_armours(std::vector<Armour>& atlas)
{
//Armour(name, description, defence, slot)
atlas.push_back(Armour("Leather Vest",
"Torso armour made of tanned hide",
4, Armour::Slot::TORSO));
return;
}
void buildatlas_area(std::vector<Area>& atlas,
std::vector<Item>& items, std::vector<Weapon>& weapons,
std::vector<Armour>& armours, std::vector<Creature>& creatures)
{
// Area definitions are somewhat more complicated:
atlas.push_back(Area(Dialogue( // Standard dialogue definiton
"You are in room 1", // Description
{ "Go to room 2", "Search" }), // Choices
Inventory( // Area inventory
{
std::make_pair(&items[0], 5) // Pair of item and quantity
},
{
std::make_pair(&weapons[0], 1)// Pair of weapon and quantity
},
{
std::make_pair(&armours[0], 1) // Pair of armour and quantity
}),
{ // Creatures
}));
atlas.push_back(Area(Dialogue(
"You are in room 2",
{ "Go to room 1", "Search" }),
Inventory(
{
std::make_pair(&items[0], 10),
std::make_pair(&items[1], 1)
},
{
},
{
}),
{
&creatures[0]
}));
return;
}
inventory.hpp:
#pragma once
#ifndef INVENTORY_HPP
#define INVENTORY_HPP
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include <list>
#include <utility>
#include <iostream>
class Inventory
{
public:
//Whilst weapons and armour are items, they have their own
//specific properties and can't be stored in the same list.
//The first element of the pair stores a pointer to the item
//in the item/weapon/armour atlas, defined in main(), the second
//if the quantity of the item
std::list<std::pair<Item*, int>> items;
std::list<std::pair<Weapon*, int>> weapons;
std::list<std::pair<Armour*, int>> armours;
Inventory(){};
Inventory(std::list<std::pair<Item*, int>> items,
std::list<std::pair<Weapon*, int>> weapons,
std::list<std::pair<Armour*, int>> armours)
{
this->items = items;
this->weapons = weapons;
this->armours = armours;
}
void add_item(Item* item, int count);
void add_weapon(Weapon* weapon, int count);
void add_armour(Armour* armour, int count);
void remove_item(Item*, int count);
void remove_weapon(Weapon*, int count);
void remove_armour(Armour*, int count);
void merge(Inventory* inventory);
void clear();
int print_items(bool label);
int print_weapons(bool label);
int print_armours(bool label);
void print(bool label);
};
//add an item to the inventory
void Inventory::add_item(Item* item, int count)
{
// Increase the quantity if the item already exists
for (auto& it : this->items)
{
if (it.first == item) it.second += count;
return;
}
// If the item doesn't already exist in the inventory, then a
// pair must be created too
this->items.push_back(std::make_pair(item, count));
}
void Inventory::add_weapon(Weapon* weapon, int count)
{
for (auto& it : this->weapons)
{
if (it.first == weapon)
{
it.second += count;
return;
}
}
this->weapons.push_back(std::make_pair(weapon, count));
}
void Inventory::add_armour(Armour* armour, int count)
{
for (auto& it : this->armours)
{
if (it.first == armour)
{
it.second += count;
return;
}
}
this->armours.push_back(std::make_pair(armour, count));
}
void Inventory::remove_item(Item* item, int count)
{
// Iterate through the items, and if they are found then decrease
// the quantity by the quantity removed
for (auto& it : this->items)
{
if (it.first == item) it.second -= count;
}
// Iterate through the list again, and remove any elements from
// the list that have zero or less for their quantity
// We do this in two passes because removing an element from
// a list during a for loop invalidates the iterators, and the
// loop stops working
this->items.remove_if([](std::pair<Item*, int>& element)
{
return element.second < 1;
});
}
void Inventory::remove_weapon(Weapon* weapon, int count)
{
for (auto& it : this->weapons)
{
if (it.first == weapon) it.second -= count;
}
this->weapons.remove_if([](std::pair<Weapon*, int>& element)
{
return element.second < 1;
});
}
void Inventory::remove_armour(Armour* armour, int count)
{
for (auto& it : this->armours)
{
if (it.first == armour) it.second -= count;
}
this->armours.remove_if([](std::pair<Armour*, int>& element)
{
return element.second < 1;
});
}
//merge the specified Inventory with the current one
//adding item quantaties if they exist, creating a new slot if they don't
void Inventory::merge(Inventory* inventory)
{
// You can't merge an inventory with itself!
if (inventory == this) return;
// Loop through the items to be added, and add them. Our addition
// function will take care of everything else for us
for (auto it : inventory->items)
{
this->add_item(it.first, it.second);
}
// Do the same for the weapons
for (auto it : inventory->weapons)
{
this->add_weapon(it.first, it.second);
}
// Do the same for the armour
for (auto it : inventory->armours)
{
this->add_armour(it.first, it.second);
}
return;
}
void Inventory::clear()
{
this->items.clear();
this->weapons.clear();
this->armours.clear();
}
//output a list of items to stdout, nicely formatted
int Inventory::print_items(bool label = false)
{
unsigned int i = 1;
for(std::list<std::pair<Item*, int>>::iterator it =
this->items.begin(); it != this->items.end(); ++it)
{
//number items if asked
if(label)
{
std::cout << i++ << ":";
//output the item name, quantity and description
std::cout << it->first->name << " (" << it->second << ") - ";
std::cout <<it->first->description << std::endl;
}
}
//return number of items outputted, for convienience
return this->items.size();
}
//output a list of weapons to stdout, nicely formatted
int Inventory::print_weapons(bool label = false)
{
unsigned int i = 1;
for (auto it : this->weapons)
{
if (label) std::cout << i++ << ": ";
std::cout << it.first->name << " (" << it.second << ") - ";
std::cout << it.first->description << std::endl;
}
return this->weapons.size();
}
//output a list of armour to stdout, nicely formatted
int Inventory::print_armours(bool label = false)
{
unsigned int i = 1;
for(std::list<std::pair<Armour*, int>>::iterator it =
this->armours.begin(); it != this->armours.end(); ++it)
{
//number items if asked
if(label)
{
std::cout << i++ << ":";
//output the item name, quantity and description
std::cout << it->first->name << " (" << it->second << ") - ";
std::cout <<it->first->description << std::endl;
}
}
//return number of items outputted, for convienience
return this->armours.size();
}
//print the entire inventory, unless it is empty
void Inventory::print(bool label = false)
{
if(this->items.size() == 0 &&
this->weapons.size() == 0 &&
this->armours.size() == 0)
{
std::cout << "Empty!" << std::endl;
}
else
{
this->print_items(label);
this->print_weapons(label);
this->print_armours(label);
}
return;
}
#endif //INVENTORY_HPP
main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <cstdlib>
#include <ctime>
#include "area.hpp"
#include "armour.hpp"
#include "atlas.hpp"
#include "creature.hpp"
#include "dialogue.hpp"
#include "inventory.hpp"
#include "item.hpp"
#include "weapon.hpp"
Creature dialogue_newChar();
int main(void)
{
std::vector<Creature> creatureAtlas;
std::vector<Item> itemAtlas;
std::vector<Weapon> weaponAtlas;
std::vector<Armour> armourAtlas;
std::vector<Area> areaAtlas;
// Build the atlases
buildatlas_creature(creatureAtlas);
buildatlas_item(itemAtlas);
buildatlas_weapon(weaponAtlas);
buildatlas_armours(armourAtlas);
buildatlas_area(areaAtlas, itemAtlas, weaponAtlas,
armourAtlas, creatureAtlas);
Creature player;
//seed rand() with system time, to produce better random numbers
srand(time(NULL));
//main game menu dialogue
int result = Dialogue("Welcome to the jungle!", { "New Game" }).activate();
switch (result)
{
case 1:
player = dialogue_newChar();
break;
default:
return 0;
break;
}
// Set the current area to be the first area in the atlas,
// essentially placing the player there upon game start
Area* currentArea = &(areaAtlas[0]);
// Play the game until a function breaks the loop and closes it
while (1)
{
// If the player has died then inform them as such and close
// the program
if (player.health <= 0)
{
std::cout << "\t----YOU DIED----\n Game Over\n";
return 0;
}
// Activate the current area's dialogue
result = currentArea->dialogue.activate();
// These could be moved inside of the area code using an
// event style system, but that allows for much less
// flexibility with what happens in each area. Since we're
// defining the areas in code anyway, sticking with this
// isn't too much of a problem, and it keeps things easy
// to understand
if (currentArea == &(areaAtlas[0]))
{
switch (result)
{
case 1:
// Move to area 1
currentArea = &(areaAtlas[1]);
break;
case 2:
// Search the area
currentArea->search(player);
break;
default:
break;
}
}
else if (currentArea == &(areaAtlas[1]))
{
switch (result)
{
// Move to area 0
case 1:
currentArea = &(areaAtlas[0]);
break;
// Search the area
case 2:
currentArea->search(player);
break;
default:
break;
}
}
}
return 0;
}
//create a new character
Creature dialogue_newChar()
{
//ask for a name and class
std::cout << "Choose your name punk!" << std::endl;
std::string name;
std::cin >> name;
int result = Dialogue("Choose your class!", { "Fighter", "Rogue" }).activate();
switch (result)
{
case 1:
//Fighter favours health and strength
return Creature(name, 35, 20, 10, 5, 10.0, 1, "Fighter");
break;
case 2:
//Rogue favours endurance and dexterity
return Creature(name, 30, 5, 10, 20, 15.0, 1, "Rogue");
break;
default:
//default should not happen, good to be safe though!
return Creature(name, 30, 10, 10, 10, 10.0, 1, "Adventurer");
break;
}
}
I can add the code for additional files if needed.
Thanks!
When you define member functions, you have the following choices to prevent multiple definitions:
Put them in the .cpp files not in the .hpp files like you have some of them now. This is the most preferred.
Put them inline in the class body. Good for one-liners in some cases.
Put them outside the class body but mark them with the inline keyword.
Right now you have member functions defined outside the class body in header files and not marked with inline. I would recommend you do #1 and move those to the .cpp files instead.
You need to move the implementation of the Inventory class methods to a .cpp file.
What's happening is that the header file is included in a few differnt .cpp files, so thise methods are compiled in several differnt compilation units. This causes the that linking error that says those methids already exist in a differnt compilation unit.
In fact all implementations except template implemtations should exist in their own .cpp files, exactly for that reason.
This problem occures when you try to include single inventory.hpp file with class Inventory methods implementation to different .cpp (main.cpp and atlas.cpp via atlas.hpp) files.
If you will separate interface and implementation of the class Inventory, then it will resolve your problem.
Separation is also important because
You hide implementation, so client code have to use an object through its public interface
It reduces building time of your project
You can change implementation .cpp file without changing interface file .hpp
More about separating you can read in article Separating Interface and Implementation in C++
I was having a similar issue. Then I realized I had multiple declarations to the .h file in separate .cpp files. This fixed the issue.
#include "*.hpp"
will define your methods multiple times. Make a *.h file, declare all methods there and use
#include "*.h"
Define your methods in a *.cpp file.

Link error 2019, prototypes are in header file though

I'm new to c++ and was just trying to do a question that involves 3 files.
I got a header file with a namespace that declares a structure and some prototypes. In definitions.cpp file, I have all the function definitions. Then the main.cpp file, just creates a few structures, calls some functions to fill the structures, then calls another function to display the structures.
The problem I have is it gives me an unresolved external error. From what I can gather I think the compiler is complaining that it cant find the prototypes for the functions being called in main.cpp - the overloaded setStruct() and the showStruct().
But I thought when I included the header.h file and declared the functions with the using declaration, in main.cpp, it gave the compiler access to the prototypes stored in the header file?
Header.h
#ifndef header_h
#define header_h
namespace SALES
{
const int QUARTERS = 4;
struct Sales
{
double sales[QUARTERS];
double average;
double max;
double min;
};
void setSales(Sales & s, const double ar[], int n);
void setSales(Sales & s);
void showSales(const Sales & s);
}
#endif
Definitions.cpp
#include<iostream>
#include"header.h"
using SALES::Sales;
using SALES::QUARTERS;
double max(Sales & s) //find max sale value in sales array
{
double maxVal = s.sales[0];
for(int i = 1; i<4;i++)
{
if(s.sales[i]>maxVal)
{
maxVal = s.sales[i];
}
}
return maxVal;
}
double min(Sales & s) //find min sale value in sales array
{
double minVal = s.sales[0];
for(int i = 1; i<4;i++)
{
if(s.sales[i]<minVal)
{
minVal = s.sales[i];
}
}
return minVal;
}
void setSales(Sales & s) // fill sales structure interactivly
{
std::cout<< "Please enter the sales for the yearly quarters.\n";
for(int i = 0;i<QUARTERS;i++)
{
std::cout<< "Quater "<<i+1<<": ";
while(!(std::cin>>s.sales[i]))
{
std::cout<<"Please enter valid input\n";
std::cout<< "Quater "<<i+1<<": ";
std::cin.clear();
std::cin.ignore();
}
}
s.average = ((s.sales[0]+s.sales[1]+s.sales[2]+s.sales[3])/4);
s.max = max(s);
s.min = min(s);
}
void setSales(Sales & s, const double ar[], int n) // fill sales structure non interactivly
{
for(int i = 0;i<n;i++)
{
s.sales[i] = ar[i];
}
for(int i = n;i<QUARTERS;i++)
{
s.sales[i] = 0;
}
s.average = ((s.sales[0]+s.sales[1]+s.sales[2]+s.sales[3])/4);
s.max = max(s);
s.min = min(s);
}
void showSales(const Sales & s) // display structure
{
std::cout<< "\nSales for the year\n";
for(int i = 0;i<QUARTERS;i++)
{
std::cout<<"Quarter "<<i+1<<": $"<<s.sales[i];
}
std::cout<<"Max Sale: "<<s.max<<std::endl;
std::cout<<"Min Sale: "<<s.min<<std::endl;
std::cout<<"Average of sales: "<<s.average<<std::endl;
}
Main.cpp
#include<iostream>
#include"header.h"
using SALES::Sales;
using SALES::setSales;
using SALES::showSales;
int main()
{
double Sales1[4] = {453.50, 654.60, 340.20, 500.30};
Sales Year1;
Sales Year2;
setSales(Year1, Sales1, 3);
setSales(Year2);
showSales(Year1);
showSales(Year2);
return 0;
}
Error
1>------ Build started: Project: Myfirst, Configuration: Debug Win32 ------
1> Main.cpp
1>Main.obj : error LNK2019: unresolved external symbol "void __cdecl SALES::setSales(struct SALES::Sales &,double const * const,int)" (?setSales#SALES##YAXAAUSales#1#QBNH#Z) referenced in function _main
1>Main.obj : error LNK2019: unresolved external symbol "void __cdecl SALES::setSales(struct SALES::Sales &)" (?setSales#SALES##YAXAAUSales#1##Z) referenced in function _main
1>Main.obj : error LNK2019: unresolved external symbol "void __cdecl SALES::showSales(struct SALES::Sales const &)" (?showSales#SALES##YAXABUSales#1##Z) referenced in function _main
1>E:\Documents\Uni\Programming\C++ starter projects\Myfirst\Debug\Myfirst.exe : fatal error LNK1120: 3 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Any help would be great, thanks.
When you define the setSales etc functions, you need to tell the compiler that they are in the SALES namespace. Putting
namespace SALES
{
// functions here
}
will do it.
You are currently defining your functions outside of any namespace, and that is the reason for the linker not finding the definitions within the namespace where those functions are declared and recognized.
The fix would be to wrap the functions in your implementation file - Definitions.cpp -, with the namespace similarly how you are doing it in the header file.
This is what I would write if I were you:
namespace SALES
{
...
void setSales(Sales & s) // fill sales structure interactivly
...
std::cout<<"Average of sales: "<<s.average<<std::endl;
}
}
If you do not put the rest (your min and max) into the namespace, use the :: scope specifier just in case, although I would suggest to put everything into your own namespace.

C++ Overloading Operator issue

So here is my header file:
#pragma once
#ifndef HYPERINT_H
#define HYPERINT_H
#include <iostream>
#include <vector>
class Hyperint
{
public:
Hyperint();
Hyperint(long a);
~Hyperint(void);
Hyperint & operator*= (const Hyperint & right);
std::vector<int> hyperintVector;
};
Hyperint operator* (const Hyperint & left, const Hyperint &right);
#endif
here is my cpp file:
#include "stdafx.h"
#include "Hyperint.h"
using namespace std;
Hyperint::Hyperint(long a)
{
//vector<int> hyperint;
int b = a;
while (b != 0){
int h = b % 10;
this->hyperintVector.push_back(h);
b = b / 10;
}
}
Hyperint::~Hyperint()
{
}
Hyperint operator*(const Hyperint & left, const Hyperint & right){
vector<int> leftVec = left.hyperintVector;
vector<int> rightVec = right.hyperintVector;
vector<int> resultVector;
Hyperint result;
int carry = 0;
int counter1 = 0;
for (vector<int>::const_iterator it = leftVec.begin(); it != leftVec.end(); ++it){
int counter2 = 0;
int totalOperand = 0;
for (vector<int>::const_iterator it2 = rightVec.begin(); it2 != rightVec.end(); ++it2){
double pow2 = pow(10, counter2);
totalOperand += ((*it2) * ((int) pow2)) * (*it);
++counter2;
}
totalOperand += carry;
int store = totalOperand % 10;
resultVector.push_back(store);
carry = totalOperand / 10;
++counter1;
}
while (carry != 0){
int putIn = carry % 10;
resultVector.push_back(putIn);
carry /= 10;
}
result.hyperintVector = resultVector;
return result;
}
Hyperint & Hyperint::operator*=(const Hyperint & right){
vector<int> rightVec = right.hyperintVector;
//vector<int> leftVec = this->hyperintVector;
vector<int> resultVector;
Hyperint theResult;
int carry = 0;
int counter1 = 0;
for (vector<int>::const_iterator it = (this->hyperintVector).begin(); it != (this->hyperintVector).end(); ++it){
int counter2 = 0;
int totalOperand = 0;
for (vector<int>::const_iterator it2 = rightVec.begin(); it2 != rightVec.end(); ++it2){
double pow2 = pow(10, counter2);
totalOperand += ((*it2) *((int)pow2)) * (*it);
++counter2;
}
totalOperand += carry;
int store = totalOperand % 10;
resultVector.push_back(store);
carry = totalOperand / 10;
++counter1;
}
while (carry != 0){
int putIn = carry % 10;
resultVector.push_back(putIn);
carry = carry/10;
}
(this->hyperintVector) = resultVector;
return *this;
}
Now the problem arises when I compile it... I get 1 error and I don't know what it is, what it means, or why and how to fix it.
Error 1 error LNK2019: unresolved external symbol "public: __thiscall Hyperint::Hyperint(void)" (??0Hyperint##QAE#XZ) referenced in function "public: class Hyperint & __thiscall Hyperint::operator*=(class Hyperint const &)" (??XHyperint##QAEAAV0#ABV0##Z) C:\Users\Drock\documents\visual studio 2013\Projects\A3-Attempt\A3-Attempt\Hyperint.obj A3-Attempt
It means that the linker is trying to look for a definition of Hyperint::Hyperint() but couldn't find it. You need to provide an implementation of it.
Linker errors can be confusing and a lot more so than compiler errors as the names get garbled and you often lose the exact location in your code that generated that error. Let's go through your error message as it contains all the information you need, just presented poorly. I'll bold the important parts.
Error 1 error LNK2019: unresolved external symbol "public: __thiscall Hyperint::Hyperint(void)" (??0Hyperint##QAE#XZ) referenced in function "public: class Hyperint & __thiscall Hyperint::operator*=(class Hyperint const &)" (??XHyperint##QAEAAV0#ABV0##Z) C:\Users\Drock\documents\visual studio 2013\Projects\A3-Attempt\A3-Attempt\Hyperint.obj A3-Attempt
In human terms, Visual Studio is complaining that it's linker encountered an error called LNK2019, which was due to not being able to find the symbol Hyperint::Hyperint(void), whilst it was going through the function Hyperint::operator*=(class Hyperint const &).
First port of call is the error number. This is easily found in a search engine, which gives the following page on MSDN: http://msdn.microsoft.com/en-us/library/799kze2z.aspx
That page describes what the error is, and gives a few examples of what kind of code generates it. This subpage describes the problem that's closer to yours: http://msdn.microsoft.com/en-us/library/x3k07566.aspx
More specifically, it couldn't find an implementation of Hyperint::Hyperint(). In C++ just declaring it (e.g. in a header as Hyperint();) is not enough, you need an implementation (the code in curly braces {}) somewhere, usually in the corresponding cpp file.
Finally, it's saying that it encountered this error whilst processing the Hyperint::operator*=(class Hyperint const &) function. This information is not actually useful in tracking down this error, but it's probably caused by this line:
Hyperint result;
Which creates a Hyperint object and initialises using the no-argument constructor, i.e. Hyperint::Hyperint().
So putting this all together, you have declared and used the no-argument constructor Hyperint::Hyperint() in your header:
class Hyperint
{
public:
Hyperint(); // < this line here
Hyperint(long a);
~Hyperint(void);
// ...
};
But you have not implemented it in your cpp file. You'd probably need something like this:
Hyperint::Hyperint()
{
// some code goes here, if required
}
You have declared a constructor Hyperint::Hyperint() that takes no arguments, but you have not provided a definition. In the .cpp file you need to provide one. You could also use a default parameter for the Hyperint::Hyperint(long) constructor (in the header file) instead if that works for your design.

LNK2019 error, unresolved external symbol

The error verbatim reads
1>yes.obj : error LNK2019: unresolved external symbol "int __cdecl availableMoves(int * const,int (* const)[4],int)" (?availableMoves##YAHQAHQAY03HH#Z) referenced in function "void __cdecl solveGame(int * const,int (* const)[4])" (?solveGame##YAXQAHQAY03H#Z)
I've never seen this error before. Here are the two functions I believe it's referring to though.
int availableMoves(int a[15], int b[36][3],int openSpace){
int count=0;
for(int i=0; i<36;i++){
if(i < 36 && b[i][2] == openSpace && isPeg(b[i][0],a) && isPeg(b[i][1],a) ){
count++;
}
}
return count;
}
and
void solveGame(int a[15], int b[36][4]) {
int empSpace;
int movesLeft;
if(pegCount(a) < 2) {
cout<<"game over"<<endl;
} else {
empSpace = findEmpty(a);
if(movesLeft = availableMoves(a,b,empSpace) < 1 ) {
temp[index] = empSpace;
d--;
c[d][0] = 0;
c[d][1] = 0;
c[d][2] = 0;
c[d][3] = 0;
a[b[c[d][3]][0]] = 1;
a[b[c[d][3]][0]] = 1;
a[b[c[d][3]][0]] = 0;
b[c[d][3]][3] = 0;
index++;
} else if(movesLeft >= 1) {
chooseMove( a, b, empSpace);
index = 0;
for(int i=0; i<4; i++) {
temp[i] = -1;
}
}
d++;
solveGame( a, b);
}
}
Your current declaration doesn't match the definition.
You probably have declared the function availableMoves() before you use it, but then you implement a different function:
int availableMoves(int* const a, int (* const)[4] , int);
//....
//....
//....
//code that uses available moves
int availableMoves(int a[15], int b[36][3],int openSpace)
{
//....
}
Since the compiler sees that declaration first, it will use it to resolve the call in the block of code. However, that function is not exported, as it has a different signature.
in solved game
b[36][4]
in available moves
b[36][3]
that could create a problem.
Nice one: you use incompatible array dimensions! Note that part of the error message reads
availableMoves(int *const,int (*const)[4],int)
While the definition of availableMoves() looks like this:
int availableMoves(int a[15], int b[36][3],int openSpace)
Although the first dimension of the arguments is ignored, all other dimensions have to match exactly. You try to call this function with incompatible dimensions, however:
void solveGame(int a[15], int b[36][4]){
...
... availableMoves(a,b,empSpace) ...