How to insert class into stl map on class initialization - c++

SOLVED: http://pastebin.com/seEaALZh
I was trying to create simple items system, where i can get item information by its id. I cant use array, because items ids are lets say random. I want to use declared items as variables and i want to quickly find any item info by its id. The only way i found is stl map.
So I have this simple code:
main.h
#include <iostream>
#include <map>
enum
{
weapon,
ammo
};
class c_items
{
bool operator()(const c_items& l, const c_items& r) const
{
return (l.id < r.id);
}
public:
c_items(void){};
c_items(int id, char name[], int type);
char *name;
int type;
int id;
};
extern std::map<int,c_items> Stuff;
c_items::c_items(int id, char name[], int type) : id(id), type(type), name(name)
{
Stuff[id] = c_items(id, name, type);
}
const c_items
brass_knuckles (546, "Brass knuckles", weapon),
golf_club (2165, "Gold club", weapon);
main.cpp
#include "main.h"
std::map<int,c_items> Stuff;
using namespace std;
int main()
{
// cout << Stuff[2165].name.data();
return 1;
}
And for some reason program crashes. How to correctly insert class data into map on class initialization?

The problem is order of initialization. The static constructors for brass_knuckles and golf_club run first, before the static constructor for Stuff, so they attempt to insert into a map that is not yet constructed.
In addition, you NEVER want variable DEFINITIONS in a header file, since if you include the header file in multiple source files, you end up with multiple definitions, which will at best cause a link failure. So you should move the DEFINITIONS out of the .h file and into the .cpp file. Putting them AFTER the definition of Stuff will fix the order of initialization problem.
You can have a DECLARATION of the variables in the header file if you want to use them in other compilation units:
extern const c_items brass_knuckles, golf_club;

you cannot put c_item in Stuff like that
instead
std::map<int,c_items> Stuff = { {item1.id, item1}, {item2.id, item2}};
but you also need to all the recommendation made by #Chris Dodd
so
c_items::c_items(int id, char name[], int type) : id(id), type(type), name(name)
{}
extern const c_items brass_knuckles, golf_club;
and in the main.cpp
const c_items brass_knuckles = {546, "Brass knuckles", weapon);
const c_items golf_club = (2165, "Gold club", weapon);
std::map<int,c_items> Stuff = { {brass_knuckles.id, brass_knuckles}, etc....};

Related

No declaration matches in Codelite IDE

I have been looking in different threads with this error which is quite common but it feels like the IDE I am using messed with my workspace and I can't quite find the problem. I am setting up an extremely basic class called "Movie" that is specified below:
Movie.hpp :
#ifndef MOVIE_HPP
#define MOVIE_HPP
#include <iostream>
#include <string>
using std::string, std::cout,std::size_t;
class Movie
{
private:
std::string name;
std::string rating;
int watched_ctr;
public:
Movie(const string& name, const string& rating, int watched_ctr);
~Movie();
//getters
string get_name() const;
string get_rating() const;
int get_watched() const;
//setters
void set_name(string name);
void set_rating(string rating);
void set_watched(int watched_ctr);
};
#endif // MOVIE_HPP
Movie.cpp:
#include <iostream>
#include <string>
#include "Movie.hpp"
using std::string, std::cout,std::size_t,std::endl;
Movie::Movie(const string& name, const string& rating, int watched_ctr)
: name(name) , rating(rating) , watched_ctr(watched_ctr) {
}
Movie::~Movie()
{
cout << "Destructor for Movies class called /n";
}
//Getters
string Movie::get_name(){return name;}
string Movie::get_rating(){return rating;}
string Movie::get_watched(){return watched_ctr;}
//Setters
void Movie::set_name(std::string n){this -> name = n;}
void Movie::set_rating(std::string rating){this -> rating = rating;}
void Movie::set_watched(int ctr){this -> watched_ctr = ctr;}
The main.cpp I am trying only consists in creating one Movie object:
#include <iostream>
#include <string>
#include "Movie.hpp"
using std::string, std::cout,std::size_t,std::endl;
int main()
{
Movie StarTrek("Star Trek", "G", 20);
}
As you can see, I set all the attribute to private in order to exercise with the set/get methods but I keep stumbling upon the same error on each of them stating >"C:/Users/.../ProjectsAndTests/MoviesClass/Movie.cpp:18:8: error: no declaration matches 'std::__cxx11::string Movie::get_name()"
if you could give me a hint on what might cause this error I would greatly appreciate thank you!
I tried opening another workspace with classes implemented inside of them and the syntax I am using is very close from this test workspace I opened which compiled fine (no error regarding declaration match).
There are 2 problems with your code.
First while defining the member functions outside class you're not using the const. So to solve this problem we must use const when defining the member function outside the class.
Second, the member function Movie::get_watched() is declared with the return type of string but while defining that member function you're using the return type int. To solve this, change the return type while defining the member function to match the return type in the declaration.
//----------------------vvvvv--------->added const
string Movie::get_name()const
{
return name;
}
string Movie::get_rating()const
{
return rating;
}
vvv------------------------------>changed return type to int
int Movie::get_watched()const
{
return watched_ctr;
}
Working demo

initializing a static (non-constant) variable of a class.

I have TestMethods.h
#pragma once
// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>
class TestMethods
{
private:
static int nextNodeID;
// I tried the following line instead ...it says the in-class initializer must be constant ... but this is not a constant...it needs to increment.
//static int nextNodeID = 0;
int nodeID;
std::string fnPFRfile; // Name of location data file for this node.
public:
TestMethods();
~TestMethods();
int currentNodeID();
};
// Initialize the nextNodeID
int TestMethods::nextNodeID = 0;
// I tried this down here ... it says the variable is multiply defined.
I have TestMethods.cpp
#include "stdafx.h"
#include "TestMethods.h"
TestMethods::TestMethods()
{
nodeID = nextNodeID;
++nextNodeID;
}
TestMethods::~TestMethods()
{
}
int TestMethods::currentNodeID()
{
return nextNodeID;
}
I've looked at this example here: Unique id of class instance
It looks almost identical to mine. I tried both the top solutions. Neither works for me. Obviously I'm missing something. Can anyone point out what it is?
You need to move the definition of TestMethods::nextNodeID into the cpp file. If you have it in the header file then every file that includes the header will get it defined in them leading to multiple defenitions.
If you have C++17 support you can use the inline keyword to declare the static variable in the class like
class ExampleClass {
private:
inline static int counter = 0;
public:
ExampleClass() {
++counter;
}
};

How do I define a datatype to be an int in a structure without redefining my class type in a class object?

I am having difficulty resolving a redefinition error. Basically, I have a class object called houseClassType in my class header file and I also have to use houseClassType as my datatype for an array within my structure in my struct header file. Below are the two header files:
house header file:
#include "Standards.h"
#ifndef house_h
#define house_h
//Definition of class, house
class houseClassType
{
//Data declaration section
private:
int capacityOfGarage;
int yearBuilt;
int listingNumber;
double price;
double taxes;
double roomCounts[3];
string location;
string style;
//Private method to set the county name
string SetCountyName(string);
string SetSchoolDistrictName(string);
//Private method to set school district name
void SetSchoolDistrictName(void);
//Set function for the object
void ExtractLocationData(string& state, string& county, string& city,
string& schoolDistrictName, string& address);
//Methods declaration
public:
///Default Constructor
houseClassType(void);
///Get methods for data members - INLINE
int GetCapacity(void) { return capacityOfGarage; };
int GetYearBuilt(void) { return yearBuilt; };
int GetListingNumber(void) { return listingNumber; };
double GetPrice(void) { return price; };
double GetTaxes(void) { return taxes; };
string GetLocation(void) { return location; };
string GetStyle(void) { return style; };
void GetRoomCounts(double[]);
//Set methods for data members
void SetCapacityOfGarage(int);
void SetYearBuilt(int);
void SetListingNumber(int);
void SetPrice(double);
void SetTaxes(double);
void SetLocation(string);
void SetStyle(string);
void SetRoomCounts(double[]);
//Output methods for data members
void OutputLocationData(ofstream&);
void OutputStyle(ofstream&);
void OutputRoomCounts(ofstream&);
void OutputCapacityOfGarage(ofstream&);
void OutputYearBuilt(ofstream&);
void OutputPrice(ofstream&);
void OutputTaxes(ofstream&);
void OutputListingNumber(ofstream&);
void OutputHouse(ofstream&);
///Destructor
~houseClassType(void);
};
#endif
Realtor header file:
#include "Standards.h"
#ifndef Realtor_h
#define Realtor_h
const int NUMBER_OF_HOMES = 30;
typedef int houseClassType;
struct realtorStructType
{
string agentName;
houseClassType homes[NUMBER_OF_HOMES]; ///Redefinition error here
int numberOfHomes;
};
void InputHomes(ifstream& fin, string agentName, int& numberOfHomes);
#endif
Any help would be much appreciated.
The C++ language likes to have unique type names throughout a translation module. The following are not unique type names:
class houseClassType
typedef int houseClassType;
If you must use the same name, then you'll need to use namespaces to separate them:
namespace City
{
class houseClassType;
}
namespace Suburban
{
typedef int houseClassType;
}
struct realtorStructType
{
Suburban::houseClassType homes[MAX_HOMES];
};
I highly recommend you draw or design this issue first. This will help you with names too.
The simple solution is to use different names.
Also, do you need the suffix "ClassType" or "StructType" in your name? In a good design, whether it be a struct or class doesn't matter.
Your code is ambiguous. If you have
class houseClassType;
typedef int houseClassType;
What would the following code mean?
houseClassType x = new houseClassType();
You can resolve the ambiguity using a namespace, but it's better to change your second houseClassType type and name.
An example might look like this.
class House {
public:
enum class Type {
...
}
};

How do I properly handle #includes in multi-file programming

First post so take it easy on me :). I don't think I really need to put up any actual code for this, but let me know if I'm wrong. This is for a homework assignment in my college programming class. I am confused as to how to properly use my #include statements. Here is my file structure:
Header Files-->
header.h (Main header file, contains #include for various libraries, declares namespace, and provides my name and class info)
room.h (Blueprint for the room class)
ship.h (Blueprint for the ship class)
Source Files-->
main.cpp (Main Program)
functions.cpp (Functions for the main program)
room.cpp (Functions in the Room class)
ship.cpp (Functions in the Ship class)
Basically, my first instinct was to " #include "header.h" " in room.h, ship.h, main.cpp, and functions.cpp. Then " #include "ship.h" in ship.cpp, and " #include room.h " in room.cpp. However I began getting errors up the wazoo. I was having a similar problem during class but I had my teacher there to sort it out and I'm not exactly sure how we did it, and I also know that tons of errors usually indicates an include error.
Its annoying because I had it working somehow before I added the functions.cpp, but I really want to keep main.cpp pretty clean, so I would rather have functions in a separate file.
What is the best pattern for includes in a situation like this?
EDIT: I'll post my 3 header files
header.h
/*
Author: *********
Class : **********
Assignment : Programming Assignment 2
Description :
This program will construct a ship for the user. It accepts input from a file
containing information on various rooms. It will then check the rooms
validity and add it to the ship if it's valid. Once all of the rooms have been added,
the program will determine if the entire ship is valid and let the user know.
Certification of Authenticity :
I certify that this is entirely my own work, except where I have given
fully - documented references to the work of others.I understand the
definition and consequences of plagiarism and acknowledge that the assessor
of this assignment may, for the purpose of assessing this assignment :
-Reproduce this assignment and provide a copy to another member of
academic staff; and / or
- Communicate a copy of this assignment to a plagiarism checking
service(which may then retain a copy of this assignment on its
database for the purpose of future plagiarism checking)
*/
#ifndef header_h
#define header_h
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
#endif
room.h
#ifndef room_h
#define room_h
#include "header.h"
enum RoomType
{
UNKNOWN = -1,
BAY,
LATRINE,
CABIN,
BRIDGE,
NUM_ROOM_TYPES
};
const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
class Room
{
public:
//default constructor
Room();
//constructor
Room( RoomType type, int width, int breadth, int height );
//destructor
~Room(){};
//accessors
inline RoomType getType() const { return mType; };
inline int getHeight() const { return mHeight; };
inline int getWidth() const { return mWidth; };
inline int getBreadth() const { return mBreadth; };
inline int getVolume() const { return getWidth() * getBreadth() * getHeight(); }; //currently unused
inline string getRoomName(){ return ROOM_STRINGS[mType]; };
string getDescription();
//mutators
void setType(RoomType type) {mType = type; };
void setHeight(int height) {mHeight = height; };
void setWidth(int width) {mWidth = width; };
void setBreadth(int breadth) {mBreadth = breadth; };
private:
//type of room
RoomType mType;
//floor dimensions - in feet
int mWidth;
int mBreadth;
//ceiling height - in feet
int mHeight;
};
#endif
ship.h
#ifndef ship_h
#define ship_h
#include "header.h"
const int MAX_BAY = 4;
const int MAX_LATRINE = 15;
const int MAX_BRIDGE = 1;
const int MAX_CABIN = 25;
const int MIN_BAY = 1;
const int MIN_LATRINE = 1;
const int MIN_BRIDGE = 1;
const int MIN_CABIN = 0;
const int MIN_ROOM_HEIGHT = 7;
const int MIN_ROOM_AREA = 20;
class Ship{
public:
Ship();
bool addRoom(const Room& theRoom);
string getDescription();
//Accessors
int getNumBays(){ return bayTotal; };
int getNumLatrines(){ return latrineTotal; };
int getNumBridges(){ return bridgeTotal; };
int getNumCabins(){ return cabinTotal; };
int getTotalSquareFootage(){ return totalSquareFootage; };
private:
Room Bay[MAX_BAY];
Room Latrine[MAX_LATRINE];
Room Bridge[MAX_BRIDGE];
Room Cabin[MAX_CABIN];
int bayTotal;
int latrineTotal;
int bridgeTotal;
int cabinTotal;
int totalSquareFootage;
bool isShipValid();
void addSquareFootage(float);
};
#endif
What kind of errors? Your issue might be including the same header more than once.
Try adding this to each header:
#ifndef ROOM_H
#define ROOM_H
... code ...
#endif
To be clear the 'ROOM_H' above needs to be unique to each header.
If you use #include "room.h" in different cpp files then you probably get a linker error because this below here is not a type declaration.
const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
You are creating and allocating a variable with name ROOM_STRINGS. By declaring it in different cpp files you will have multiple copies of the same global variable which is an error. You could replace it with
static const string ROOM_STRINGS[NUM_ROOM_TYPES] = { "Bay",
"Latrine",
"Cabin",
"Bridge"
};
You will still have multiple copies but each cpp file will have its own private copy. A better solution is to move this declaration into the room cpp file together with the code of the getRoomName.
Or you could declare ROOM_STRINGS as extern in the header and then you still need to add the variable allocation in a cpp file.

C++ Cannot use push_back on list containing custom structs

We are making a list that hold info on boardgames (name, year, score). We scan the info out of a .csv file, make a struct based on that info and then add the struct to a list. We keep doing this untill the document is done reading. Problem is that the push_back method of the list doesn't work. Here's the header of the list class:
NOTE BoardGame is the custom struct. BoardGame(wstring name, int year, float score).
#pragma once
#include "GameEngine.h"
#include "BoardGame.h"
#include <list>
class BoardGameList
{
public:
BoardGameList() {}
virtual ~BoardGameList() {}
// Methods
void Load(const tstring& fileName);
// Members
private:
std::list<BoardGame> m_Games;
};
The cpp file. Maybe I made the list the wrong way?
#include "BoardGameList.h"
#include <fstream>
void BoardGameList::Load(const tstring& fileName)
{
tifstream file(fileName);
tstring line;
if(!file)
{
GAME_ENGINE->MessageBox(_T("Error: The file could not be found!"));
}
else
{
tstring name;
tstring year;
tstring score;
while(!(file.eof()))
{
getline(file,line);
year = line.substr(0,4);
score = line.substr(5,5);
name = line.substr(11,line.find(_T("\n")));
float numberScore = std::stof(score);
int numberYear = std::stoi(year);
m_Games.push_back(BoardGame(name,numberYear,numberScore));
}
}
}
Running the program triggers an error (unhandled exception) that leads me to the following code in the "list" class itself I think.
_Unchecked_iterator _Unchecked_end()
{ // return unchecked iterator for end of mutable sequence
return (_Unchecked_iterator(this->_Myhead, this));
}
Any ideas why I can't add stuff to my list? I tried adding something in the constructor to check if it maybe needed an element before I could add more but even then, using a breakpoint showed me that the memory could not be read.
Many thanks in advance.
EDIT: Header of BoardGame
#pragma once
#include "GameEngine.h"
struct BoardGame
{
BoardGame(tstring name, int year, float score);
//Methods
tstring operator<<(BoardGame rhs);
//Members
tstring m_Name;
int m_Year;
float m_Score;
};
What exception is being thrown? This is vital to debugging your problem.
Without that information my best guess is this line:
name = line.substr(11,line.find(_T("\n")));
Will throw an exception on any line without a trailing newline, or any line less than 11 characters long.