This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 11 months ago.
This is basically two errors in one, that seem to come from the same thing. If I define my functions in my main.cpp file, and forward declare them at the top of the file, it doesn't give me any errors and everything runs smoothly.
When trying to declutter and move things into seperate .cpp files, it starts to give me linker errors and saying things are undefined even though I am using appropriate header files. The code is shown below:
main.cpp
#include "io.h"
#include <iostream>
#include <map>
class exchangeRates;
void menu();
int main()
{
menu();
return EXIT_SUCCESS;
}
// class storing exchange rates
class exchangeRates
{
public: // Access specifier
// Data Members
std::map<std::string, double> usd = {
{"GBP", 1.2},
{"EUR", 0.7},
};
std::map<std::string, double> gbp = {
{"USD", 0.9},
{"EUR", 1.4},
};
};
// menu function
void menu()
{
// get reference currency code from user
std::string refCurrency{ obtainCodeFromUser() };
// create 'rates' instance of 'exchangeRates' class
exchangeRates rates{};
// print the exchange values for that currency
if (refCurrency == "USD")
{
printExchangeValues(rates.usd, refCurrency);
}
else if (refCurrency == "GBP")
{
printExchangeValues(rates.gbp, refCurrency);
}
else
{
std::cout << "\nInvalid currency code. Example: USD, GBP, EUR etc.\n\n";
menu();
}
}
io.h
#ifndef IO_H
#define IO_H
#include <iostream>
#include <map>
std::string obtainCodeFromUser();
double obtainAmountFromUser();
template<typename Map>
void printExchangeValues(Map& valuedCurrencies, std::string refCurrency);
#endif
io.cpp
#include "io.h"
#include <iostream>
#include <map>
// io functions for currency converter
std::string obtainCodeFromUser()
{
// obatin reference currency code from user
std::cout << "Enter currency code for reference currency (case-sensitive): ";
std::cin.clear();
std::string refCurrency{};
std::cin >> refCurrency;
std::cin.ignore(INT_MAX, '\n');
return refCurrency;
}
double obtainAmountFromUser()
{
// obtain amount of currency to be converted from user
std::cout << "Enter amount of currency to convert: ";
std::cin.clear();
double amount{};
std::cin >> amount;
std::cin.ignore(INT_MAX, '\n');
return amount;
}
template<typename Map>
void printExchangeValues(Map& valuedCurrencies, std::string refCurrency)
{
// obtain amount of currency to be converted
double amount{ obtainAmountFromUser() };
std::cout << refCurrency << " " << amount << " is worth:\n";
for (auto& item : valuedCurrencies) {
std::cout << item.first << ": " << amount * item.second << '\n';
}
}
I am still a beginner with C++ so some parts have been copied from other open-source programs, and I know there are probably plenty of places to improve my code, but I'm mainly interested in why it just won't compile. The examples I followed when learning how to use header files worked fine and I don't believe I've done anything different here.
It says the identifiers "obtainCodeFromUser" and "printExchangeValues" are undefined.
The linker error it gives is LNK2019 'unresolved external symbol ...' and it seems to be relating to the printExchangeValues function.
Any help is massively appreciated!
The issue mentioned by WhozCraig is very useful, I hope you will read it carefully. Regarding your question, after I modified some code, the program can run correctly. The error is caused by the template. Since you are a beginner and the program is not very complicated, the following code is more convenient for you to understand:
main.cpp
#include "io.h"
#include <iostream>
#include <map>
// class storing exchange rates
class exchangeRates
{
public: // Access specifier
// Data Members
std::map<std::string, double> usd = {
{"GBP", 1.2},
{"EUR", 0.7},
};
std::map<std::string, double> gbp = {
{"USD", 0.9},
{"EUR", 1.4},
};
};
template<typename Map>
void printExchangeValues(Map& valuedCurrencies, std::string refCurrency)
{
// obtain amount of currency to be converted
double amount{ obtainAmountFromUser() };
std::cout << refCurrency << " " << amount << " is worth:\n";
for (auto& item : valuedCurrencies) {
std::cout << item.first << ": " << amount * item.second << '\n';
}
}
// menu function
void menu()
{
// get reference currency code from user
std::string refCurrency{ obtainCodeFromUser() };
// create 'rates' instance of 'exchangeRates' class
exchangeRates rates{};
// print the exchange values for that currency
if (refCurrency == "USD")
{
printExchangeValues(rates.usd, refCurrency);
}
else if (refCurrency == "GBP")
{
printExchangeValues(rates.gbp, refCurrency);
}
else
{
std::cout << "\nInvalid currency code. Example: USD, GBP, EUR etc.\n\n";
menu();
}
}
int main()
{
menu();
return EXIT_SUCCESS;
}
io.h
#ifndef IO_H
#define IO_H
#include <iostream>
#include <map>
std::string obtainCodeFromUser();
double obtainAmountFromUser();
#endif
io.cpp
#include "io.h"
#include <iostream>
#include <map>
// io functions for currency converter
std::string obtainCodeFromUser()
{
// obatin reference currency code from user
std::cout << "Enter currency code for reference currency (case-sensitive): ";
std::cin.clear();
std::string refCurrency{};
std::cin >> refCurrency;
std::cin.ignore(INT_MAX, '\n');
return refCurrency;
}
double obtainAmountFromUser()
{
// obtain amount of currency to be converted from user
std::cout << "Enter amount of currency to convert: ";
std::cin.clear();
double amount{};
std::cin >> amount;
std::cin.ignore(INT_MAX, '\n');
return amount;
}
Related
I am working on some code to make a wallet to hold different currencies and this is my first time programming in c++ as a c programmer. Every time I make a new currency I want to add it to the list of valid Currencies that my wallet will be able to hold. To do this I make a currency class with a list that I want to add to every time a new currency is spawned. The error I get is error: no matching function for call to ‘std::__cxx11::list<Currency>::push_back(Currency*) CurrencyList.push_back(this);"\
Currency.h looks like:
#ifndef CURRENCY_H
#define CURRENCY_H
#include <string>
#include <list>
class Currency {
public:
//Instances of class
int id;
float max;
float left_over;
std::string coinName;
//Methods
float buyFrom(float amount);
float sellBack(float amount);
//constructor
Currency();
};
extern std::list<Currency> CurrencyList; //global list
#endif
Currency.c looks like
#include "currency.h"
#include <iostream>
Currency::Currency() {
Currency::id = 0;
std::cout << "Input name :" << std::endl;
std::cin >> Currency::coinName;
std::cout << "Input max :" << std::endl;
std::cin >> Currency::max;
Currency::left_over = Currency::max - 0;
CurrencyList.push_back(this);
}
float Currency::buyFrom(float amount) {
Currency::left_over-=amount;
std::cout << "Currency just lost :" << amount << "remaining is : " << Currency::left_over << std::endl;
}
float Currency::sellBack(float amount) {
Currency::left_over -= amount;
std::cout << "Currency just gained : " << amount << " remaining is : " << Currency::left_over << std::endl;;
}
The main is quiet simple it is only meant to spawn an object to test, that looks something like this.
Main.cpp
#include <iostream>
#include "wallet.h"
#include "currency.h"
int main(){
std::cout << "Hello World" << std::endl;
Currency currencyTest;
currencyTest.buyFrom(200.3);
}
Note that this is a pointer, but your list holds actual objects, not pointers.
So just dereference the pointer and you should be fine:
CurrencyList.push_back(*this);
I have a banking project and I am trying to set up the bank name, address, and working hours. My getlines are showing an error as well as my get functions.
Input exact error messages here please.
'getline': no matching overloaded function found
no suitable user-defined conversion from "Bank" to "std::string" exists
Here's the class for bank:
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <cctype>
#include <cstdlib>
using namespace std;
class Bank {
public:
void setBankName(string bn) { bn = bankname; }
string getBankName() { return bankname; }
void setBankAdd(string ba) { ba = bankadd; }
string getBankAdd() { return bankadd; }
void setWorkingHours(string bwh) { bwh = bankworkinghours; };
string getWorkingHours() { return bankworkinghours; }
private:
string bankname, bankadd, bankworkinghours;
};
//and then this is in my main function
int main() {
Bank bankname, bankadd, bankworkinghours;
char userChoice; // numbers 1-9
int number=0;
system ("color 5f");
cout << "Name of bank: ";
getline(cin, bankname); **//all the get lines also show error**
cout << endl;
cout << "Bank address: ";
getline(cin, bankadd);
cout << endl;
cout << "Bank working hours: ";
getline(cin, bankworkinghours);
cout << endl;
bankname.setBankName(bankname); //the things in the parentheses show error
bankadd.setBankAdd(bankadd);
bankworkinghours.setWorkingHours(bankworkinghours);
The error is self explanatory. 2nd parameter of getline function is std:string so define bankname as std:string and then set the name of bank object by setBankName.
1- You did not created bank Object in the main to set class attributes.
You need an Object with reference to that object you will set the parameters of the class bank.
2- bankname, bankadd, bankworkinghours are string and you made them Bank
Here is updated code and working fine in VS 2019 without any error. Just a few changes in the first 2 and last three lines of main
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <cctype>
#include <cstdlib>
using namespace std;
class Bank {
public:
void setBankName(string bn) { bn = bankname; }
string getBankName() { return bankname; }
void setBankAdd(string ba) { ba = bankadd; }
string getBankAdd() { return bankadd; }
void setWorkingHours(string bwh) { bwh = bankworkinghours; };
string getWorkingHours() { return bankworkinghours; }
private:
string bankname, bankadd, bankworkinghours;
};
//and then this is in my main function
int main() {
Bank bankObj;
string bankname, bankadd, bankworkinghours;
char userChoice; // numbers 1-9
int number = 0;
system("color 5f");
cout << "Name of bank: ";
getline(cin, bankname);
cout << endl;
cout << "Bank address: ";
getline(cin, bankadd);
cout << endl;
cout << "Bank working hours: ";
getline(cin, bankworkinghours);
cout << endl;
bankObj.setBankName(bankname);
bankObj.setBankAdd(bankadd);
bankObj.setWorkingHours(bankworkinghours);
}
void setBankName(string bn) { bn = bankname; } is the wrong way around. try bankname = bn.
I'm learning C++, and I'm just messing around with putting classes in separate files for practice. I have a getter function, which returns a string (because the variable is saved as a string). However, from my main() function, I am not sure how to call it. I know the problem is probably that I need to include string somewhere when I call the object, but I have no idea how to format it.
I know this is a pretty newbie questions, but I couldn't find the answer anywhere. Could someone help me out?
(p.s. I'm not trying to get this specific code to work, since it's useless. I'm just trying to learn how to apply it for future reference).
I've tried throwing in string in a couple of places when calling or creating the object, but I always get an error. I know I could get around it by not encapsulating the variable or not having a separate class file, but that's not what I want.
main.cpp
#include <iostream>
#include "usernameclass.h"
#include <string>
using namespace std;
int main()
{
usernameclass usernameobject;
usernameobject.getUsername();
return 0;
}
usernameclass.h
#ifndef USERNAMECLASS_H
#define USERNAMECLASS_H
#include <string>
class usernameclass
{
public:
usernameclass();
std::string getUsername();
void setUsername(std::string name);
askUsername();
private:
std::string usernameVar = "test";
};
#endif
usernameclass.cpp
#include "usernameclass.h"
#include <iostream>
#include "username.h"
#include <string>
using namespace std;
string usernameclass::getUsername(){
return usernameVar;
cout << "test cout" << endl;
}
usernameclass::askUsername(){
string name;
cout << "What is your name?" << endl;
cin >> name;
setUsername(name);
cout << "Ah, so your name is "+usernameVar+", great name I guess!" << endl;
cin.get();
cin.get();
cout << "You're about to do some stuff, so get ready!" << endl;
}
usernameclass::usernameclass(){}
void usernameclass::setUsername(string name){
string* nameptr = &usernameVar;
*nameptr = name;
}
Expected result: runs getUsername() function and returns usernameVar
Actual result: doesn't run the getUsername() function
The current code would not compile, because you have not specified return type of 'askUsername()' routine, which is 'void', I believe.
Other things are good, apart from an output in 'getUsername()', which happens after returning from the function and about which you should have received a warning, I guess.
To the question: you can call that 'get' method in 'main()' as:
cout << usernameobject.getUsername();
Your code should be structured more like this instead:
main.cpp
#include <iostream>
#include "usernameclass.h"
int main()
{
usernameclass usernameobject;
// optional:
// usernameobject.askUsername();
// do something with usernameobject.getUsername() as needed...
return 0;
}
usernameclass.h
#ifndef USERNAMECLASS_H
#define USERNAMECLASS_H
#include <string>
class usernameclass
{
public:
std::string getUsername() const;
void setUsername(std::string name);
void askUsername();
private:
std::string usernameVar = "test";
};
#endif
usernameclass.cpp
#include <iostream>
#include "usernameclass.h"
std::string usernameclass::getUsername() const {
return usernameVar;
}
void usernameclass::setUsername(std::string name) {
usernameVar = name;
}
void usernameclass::askUsername() {
std::string name;
std::cout << "What is your name?" << std::endl;
std::getline(std::cin, std::name);
setUsername(name);
std::cout << "Ah, so your name is " << getUsername() << ", great name I guess!" << std::endl;
std::cout << "You're about to do some stuff, so get ready!" << std::endl;
}
I have this batting average program. My problem is that I cannot output this program using input/output files so that it shows the highest/lowest averages and the names to go with them. The code I have in main is not right because it is only outputting "Highest batting average is: 0" and "Players with the highest batting average: " None of the averages are 0 so it should not be outputting that, and there should be a name next to the highest batting average. The same goes with the lowest. This is what I have so far:
#include "Player.h"
#include "Stack.h"
#include <fstream>
using namespace std;
int main()
{
Player x;
string name;
double avg;
ifstream infile("avgs.txt");
while (infile >> name >> avg)
{
x.insertPlayer(name, avg);
}
infile.close();
x.printHigh();
x.printLow();
if(!infile)
{
cout << "Unable to open the file for writing " << endl;
exit(0);
}
ofstream outfile("avgs.txt");
if (!outfile)
{
cout << "Error opening file " << endl;
exit(0);
}
outfile << endl;
}
Here are the files to the Player class, and the Stack class in case it is needed aswell:
////Player.h
#include "stdafx.h"
#include <iostream>
#include <string>
#include "Stack.h"
using std::string;
class Player
{
public:
double lowest;
double highest;
Stack<string> low;
Stack <string> high;
void insertPlayer(string name, double batAvg);
void printHigh();
void printLow();
};
This is the .cpp file for the Player class:
#include "stdafx.h"
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
using std::string;
void Player::insertPlayer(string name, double batAvg)
{
cout << "Player " << name << " has an average of: " << batAvg << endl;
if (low.empty() && high.empty())
{
low.push(name);
high.push(name);
highest = lowest = batAvg;
}
else
{
if (batAvg>highest)
{
while (!high.empty())
high.pop();
highest = batAvg;
high.push(name);
}
else if (batAvg == highest)
high.push(name);
else if (batAvg<lowest)
{
while (!low.empty())
low.pop();
lowest = batAvg;
low.push(name);
}
else if (batAvg == lowest)
low.push(name);
}
}
void Player::printHigh()
{
cout << "Highest batting average is: " << highest << endl;
cout << "Players with the highest batting average: " << endl;
}
void Player::printLow()
{
cout << "Lowest batting average is: " << lowest << endl;
cout << "Players with the lowest batting average: " << endl;
}
And my Stack class if it is needed:
#ifndef STACK
#define STACK
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Stack : public exception
{
private:
vector<T>myStacks;
public:
void push(T const& uStack);
void pop();
T peek() const;
bool empty() const
{
return myStacks.empty();
}
};
template <class T>
void Stack<T>::push(T const& uStack)
{
myStacks.push_back(uStack);
}
template <class T>
void Stack<T>::pop()
{
if (myStacks.empty())
{
throw std::out_of_range("Stack <>::pop(): This is an empty stack ");
}
myStacks.pop_back();
}
template <class T>
T Stack<T>::peek() const
{
if (myStacks.empty())
{
throw std::out_of_range("Stack<>::peek(): This is an empty stack ");
}
return myStacks.back();
}
#endif
The focus code that I am trying to output is Player.cpp, but the Stack.h and Player.h are needed to make it run. In main() I need to output the names, averages, and the people with the highest/lowest averages. Any help is appreciated!
The text file consists of players and their averages, for example:
Orlando .775
Charles .606
J.D. .775
Gina .400
Sam .702
Rich .686
and so on.
The first thing you want to do is remove everything after x.printLow(); in main, then verify that the expected input is present in avgs.txt.
Your code will overwrite the input file with a single newline, so if you have tried it once, you probably haven't got the input you expect anymore. Notice how you never see output from cout << "Player " << name << " has an average of: " << batAvg << endl;. That indicates insertPlayer is not being called.
I'm pretty sure it is a problem with finding your input file, as it works with a different input source. Is the file with the text in the same folder as your .exe? Is it instead in a different folder, such as where the source files are?
A simple test would be to just copy the contents of the file to cout, to see what the program finds
int main() {
std::ifstream infile("avgs.txt");
for (std::string line; std::getline(infile, line;) {
std::cout << line << std::endl;
}
}
Struct Problem 1.cpp
// Struct Problem 1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "structs.h"
double calculateEarnings(Advertising aDay);
void displayEarnings(int questionInstance, Advertising aDay);
void mainQuestions();
int _tmain(int argc, _TCHAR* argv[])
{
mainQuestions();
return 0;
}
double calculateEarnings(Advertising aDay)
{
std::cout << aDay.usersClicked; //debug
return aDay.totalAdsShown * aDay.usersClicked * aDay.averagePerAd;
}
void takeInData(int questionInstance, Advertising aDay)
{
if (questionInstance == 0)
{
std::cin >> aDay.totalAdsShown;
}
else
if (questionInstance == 1)
{
std::cin >> aDay.usersClicked;
}
else
if (questionInstance == 2)
{
std::cin >> aDay.averagePerAd;
}
std::cin;
}
void mainQuestions()
{
static Advertising aToday;
aToday.totalAdsShown = 0;
aToday.usersClicked = 0.00;
aToday.averagePerAd = 00.00;
std::cout << "Welcome! Please input the advertising data for today." << "\n";
std::cout << "How many ads were shown today?" << "\n";
takeInData(0, aToday);
std::cout << "What percentage of users clicked our ads? (decimal form)" << "\n";
takeInData(1, aToday);
std::cout << "What were the average earnings per ad? (ex: 5.15)" << "\n";
takeInData(2, aToday);
structs.h
#ifndef STRUCTS_H
#define STRUCTS_H
typedef double percentage;
typedef double USD;
struct Advertising
{
int totalAdsShown;
percentage usersClicked;
USD averagePerAd;
};
#endif
Basically, the data is not saved when called by 'cin'. I added a line to print the aDay.usersClicked value and it prints to 0. I am learning c++, so the problem is very basic. I appreciate all tips!
Thank you
Change this:
void takeInData(int questionInstance, Advertising aDay)
into this:
void takeInData(int questionInstance, Advertising& aDay)
and it will work. The reason is that in your version, the paramater aDay is passed-by-value; i.e. a copy of the argument is passed to the function. So anything that takeInData() does to its version of aDay is done in the copy. After takeInData() returns, the copy (and the information therein) is lost.
In the edited version, a reference to aDay is passed to the function. Now it will reference the variable that was passed, i.e. the variable in main(). Now all things takeInData() does, are stored in the value that is actually declared in main().