I would like to use a string before .getName()
Enemy Troll(Troll, 250, 30);
string enemyName;
enemyName = Troll;
enemyName.getName(); //this is causing the error... "No member named 'setHP' in 'std::__1::basic_string<char>'"
I want to be able to get the same results as using Troll.getName(); but instead use a string.
There is no built in way in C++ to use a string to look up a variable of the same name in C++.
What you have to do is create the appropriate data structure for yourself. One way to do that would be to use a map.
#include <map>
std::map<std::string, Enemy> my_map;
...
Enemy trump("Trump", 250, 30);
my_map["Trump"] = trump;
...
std::string name = ...;
Enemy some_enemy = my_map[name];
You can store all the instances by name as a static data member in a map for example. But there should be better ways to do it depending on the complete design of your program. But since you didn't provide all the context I'm just going to show a generic example. With some issues like non thread safety, missing null checks, not dealing with duplicates, etc.
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Enemy{
public:
std::string m_name;
int m_hp;
int m_dmg;
static std::map<std::string,Enemy*> s_instances;
Enemy(const std::string& name, int hp, int dmg)
: m_name(name),
m_hp(hp),
m_dmg(dmg)
{
s_instances[name] = this;
}
~Enemy()
{
s_instances.erase(m_name);
}
const std::string& getName() const
{
return m_name;
}
static Enemy* getInstanceByName(const std::string& name)
{
Enemy* result = nullptr;
auto iter = s_instances.find(name);
if(iter!=s_instances.end()) result = iter->second;
return result;
}
};
std::map<std::string,Enemy*> Enemy::s_instances;
void doStuff()
{
Enemy* instance = Enemy::getInstanceByName("Ork");
std::cout << instance->getName();
}
int main() {
Enemy ork("Ork",300,20);
doStuff();
return 0;
}
Related
I am working through this problem I found on Git to brush up on some skills. Using friend is prohibited. C++ styling should be used compared to C.
Essentially, I cannot call the identify() function that belongs to the Brain member variable in my Human class. It just will not let me access it. If you can code this up, and explain where I am going wrong, that would be great.
Create a Brain class, with whatever you think befits a brain. It will have an Identify() function that returns a string containing the brain's address in memory, in hex format, prefixed by 0x.
Then, make a Human class, that has a constant Brain attribute with the same lifetime. It has an identify() function, that just calls the identity() function of its Brain and returns its result.
Now, make it so this code compiles and displays two identical addresses:
int main(){
Human bob;
std::cout << bob.identify() << "\n";
std::cout << bob.getBrain().identify() << "\n";
}
Here is what I have so far:
#pragma once
#include "Brain.h"
class Human
{
const Brain humanBrain;
public:
Human();
std::string identify();
};
#include "Human.h"
#include <iostream>
#include <string>
#include <sstream>
Human::Human()
{
this->humanBrain = new Brain;
}
std::string Human::identify()
{
Brain b = this->humanBrain.identify(); // This is essentially what I am trying to call--and I can't access it.
const Brain * ptr = humanBrain;
std::ostringstream test;
test << ptr;
return test.str();
}
#pragma once
#include <string>
#include <iostream>
class Brain
{
int age;
std::string gender;
void* ptr;
public:
Brain();
//std::string getBrain();
const std::string identify();
void setPtr(void* p);
};
#include "Brain.h"
#include <iostream>
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
const std::string Brain::identify()
{
//const Brain* bPtr = &this;
const Brain* bPtr = this;
ptr = this;
std::ostringstream test;
test << &bPtr;
std::string output = "Brain Identify: 0x" + test.str();
return output;
}
Your Human::humanBrain member is declared as type const Brain, which is correct per the instructions, however your Brain::identify() method is not qualified as const, so you can't call it on any const Brain object. This is the root of the problem that you are having trouble with.
In addition, there are many other problems with your code, as well:
Human::humanBrain is not a pointer, so using new to construct it is wrong. And, you don't need a pointer to get the address of a variable anyway. Nor do you actually need a pointer to the member at all in this project.
Human lacks a getBrain() method, so bob.getBrain() in main() will not compile, per the instructions.
Human::identify() is calling humanBrain.identify(), which returns a std::string as it should, but is then assigning that string to a local Brain variable, which is wrong (not to mention, you are not even using that variable for anything afterwards). The instructions clearly state that Human::identity() should simply call Brain::identify() and return its result, but you are not doing that.
Brain::identify() is printing the address of its local variable bPtr rather than printing the address of the Brain object that identify() is begin called on, per the instructions.
With all of that said, try something more like this instead:
Human.h
#pragma once
#include "Brain.h"
#include <string>
class Human
{
const Brain humanBrain;
public:
Human() = default;
std::string identify() const;
const Brain& getBrain() const;
};
Human.cpp
#include "Human.h"
std::string Human::identify() const
{
return humanBrain.identity();
}
const Brain& Human::getBrain() const
{
return humanBrain;
}
Brain.h
#pragma once
#include <string>
class Brain
{
int age;
std::string gender;
public:
Brain();
std::string identify() const;
};
Brain.cpp
#include "Brain.h"
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
std::string Brain::identify() const
{
std::ostringstream test;
test << "Brain Identify: 0x" << this;
return test.str();
}
I need to get in a vector the names of some cities as soon as they are created... In order to accomplish that I created a static vector for the class City, however when I try to compile my code I get the error
error: lvalue required as unary '&' operand
this->cities.push_back(&this);
^~~~
What am I doing wrong?
My code is the following...
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
this->cities.push_back(&this);
};
~City(){};
} hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}
this is already a City* pointer, so drop the & from &this.
Also, don't forget to actually define the static vector object.
Also, you should account for the class' copy/move constructors and destructor, to make sure you don't miss adding pointers, or leave behind dangling pointers.
Try this:
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
cities.push_back(this);
}
City(const City &src) : name{src.name}
{
cities.push_back(this);
}
City(City &&src) : name{std::move(src.name)}
{
cities.push_back(this);
}
~City()
{
cities.erase(std::find(cities.begin(), cities.end(), this));
}
};
vector<City *> City::cities;
City hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}
#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int ID;
string name;
public:
Test(int ID, string name);
};
Test::Test(int ID, string name)
{
this->ID = ID;
this->name = name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID << endl;
return 0;
}
This is a simple code I'm trying.
I want to access to the data that I stored in vector.
I thought it would be accessible by using -> just like vector of struct but I can't. So I want to know how to load the data in class.
In addition, I thought sending data to heap section using new would make it accessible at any time I want regardless of whether it is private or public, but it seems like it is not possible.
Can you explain how it works?
(I don't even fully understand how class work, so detailed explanation would be very appreciated. Thx!)
A private variable cannot be accessed by code outside the class definition. (There are exceptions with friend)
ptr->ID does not work because main is outside the class definition.
This can be fixed by using a getter method.
#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int _ID;
string _name;
public:
int ID() {return _ID;}
string name() {return _name;}
Test(int param_ID, string param_name);
};
Test::Test(int param_ID, string param_name)
{
_ID = param_ID;
_name = param_name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID() << endl;
return 0;
}
The above example shows the getter methods ID() and name() which return the data members _ID and _name respectively.
ID() is allowed to access _ID because ID() is part of the class definition. name() is allowed to access _name because name() is part of the class definition.
Note: I would still consider this code to be flawed because it creates a new object on the heap, but does not delete it. You should also look up the keywords new and delete to see how they operate together.
Static1.hpp
#include <string>
class Static1
{
public:
static const std::string my_string;
};
Static1.cpp
#include "Static1.hpp"
const std::string Static1::my_string = "aaa";
Static2.hpp
#include <string>
class Static2
{
public:
static const std::string my_string;
};
Static2.cpp
#include "Static2.hpp"
const std::string Static2::my_string = Static1::my_string;
main.cpp
#include "Static2.hpp"
#include <iostream>
int main(argc int, char** argv)
{
cout << to_string(Static2::my_string == "aaa") << endl;
return 0;
}
If I put add_executable(printMyString main.cpp Static2.cpp Static1.cpp) in my CMakeLists.txt, I get
0
while add_executable(printMyString main.cpp Static2.cpp Static1.cpp) gives me the expected behavior of
1
To make my code easier to maintain (so that I don't need to keep track of the order I list my source files), is there any way I can ensure that I get the behavior where Static2::my_string == "aaa"?
You are experiencing effects of a static initialization order fiasco.
The usual work-around is to substitute your static variables with functions that have a static variable in the scope, initialize, and return it.
Here is how it could be done for your example: Live Example (order1)
Live Example (order2)
class Static1
{
public:
static std::string my_string();
};
...
std::string Static1::my_string()
{
static const std::string my_string = "aaa";
return my_string;
}
...
class Static2
{
public:
static std::string my_string();
};
...
std::string Static2::my_string()
{
static const std::string my_string = Static1::my_string();
return my_string;
}
...
std::cout << std::to_string(Static2::my_string() == "aaa") << std::endl;
I'm trying to implement a class (C++) with an enum (with the permitted parameters). I got a working solution, but if I try to extend the functionality I get stuck.
Header data_location.hpp
class DataLocation
{
private:
public:
enum Params { model, period };
std::string getParamString(Params p);
};
Program data_location.cpp
string DataLocation::getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
The array ParamsStrings should be generally available in the class, because I need a second method (with inverse function) returning the enum value given a string.
If I try to define the array in the header I get the error:
in-class initialization of static data member ‘const char* DataLocation::ParamsStrings []’ of incomplete type
Why is the type incomplete? The compiler is for sure able to counts the strings in the array, isn't it?
In case there is no way to get my code working, is there an other way? With 1) no XML; 2) no double definition of the strings; 3) not outside the class; 4) no in code programmed mapping.
In class (header) use keyword static and initialize it outside (.cpp) without the static keyword:
class DataLocation {
public:
enum Params { model, period };
string getParamString(Params p);
static const char* ParamsStrings[];
// ^^^^^^
};
const char* DataLocation::ParamsStrings[] = {"MODEL", "BLLBLA"};
//^^^^^^^^^^^^^^^^^^^^^^^^
The code you have posted is perfectly fine.
Here's the proof:
#include <iostream>
#include <string>
struct DataLocation
{
enum Params { model, period };
std::string getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
};
int main()
{
auto a = DataLocation();
std::cout << a.getParamString(DataLocation::model) << std::endl;
return 0;
}
The error message you are getting is not to do with definition of a static data member in an inline function - that's allowed.
There's something else you're not showing us.
The main issue in my question (the second part) was that if I split the class in .hpp and .cpp the definition of the array (I mixed *char and string) has also to be split:
// data_location.hpp
class DataLocation {
static const char * ParamsStrings[];
}
// data_location.cpp
const char * ParamsStrings[] = {"MODEL", "PERIOD"};
At the end I introduced a consistency check to be sure that the number of values in enum growths as the number of strings. Because the array in C++ is somehow limited I had to go for a std::vector (to get the size).
Code for data_location.hpp
#ifndef DATA_LOCATION_HPP_
#define DATA_LOCATION_HPP_
#include <string>
#include "utils/dictionary.hpp"
extern const char* ENV_DATA_ROOT;
struct EDataLocationInconsistency : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct EDataLocationNotValidParam : std::runtime_error
{
using std::runtime_error::runtime_error;
};
class DataLocation
{
private:
std::string mRootLocation;
static const std::vector<std::string> msParamsStrings;
static bool msConsistenceCheckDone;
public:
DataLocation();
std::string getRootLocation();
std::string getLocation(Dictionary params);
enum Params { model, period, LAST_PARAM};
std::string Param2String(Params p);
Params String2Param(std::string p);
};
#endif
Code for data_location.cpp
#include "data_location.hpp"
#include <string>
#include <cstdlib>
using namespace std;
const char* ENV_DATA_ROOT = "DATA_ROOT";
bool DataLocation::msConsistenceCheckDone = false;
DataLocation::DataLocation() {
mRootLocation = std::getenv(ENV_DATA_ROOT);
if (not msConsistenceCheckDone) {
msConsistenceCheckDone = true;
if (LAST_PARAM+1 != msParamsStrings.size()) {
throw(EDataLocationInconsistency("DataLocation: Check Params and msParamsStrings"));
}
}
}
string DataLocation::getRootLocation() {
return mRootLocation;
}
string DataLocation::getLocation(Dictionary params) {
// to do
return "";
}
const vector<string> DataLocation::msParamsStrings = { "MODEL", "PERIOD", ""};
string DataLocation::Param2String(Params p) {
if (p>=msParamsStrings.size()) {
throw(EDataLocationNotValidParam("Parameter not found"));
}
return msParamsStrings[p];
}
DataLocation::Params DataLocation::String2Param(string p) {
for (int i = 0; i < msParamsStrings.size(); i++) {
if (p == msParamsStrings[i])
return (Params)i;
}
throw(EDataLocationNotValidParam("Parameter not found"));
}
And also a unit test:
#include <boost/test/unit_test.hpp>
#include "data_location.hpp"
#include <string>
using namespace std;
BOOST_AUTO_TEST_SUITE( data_location )
BOOST_AUTO_TEST_CASE(data_location_1) {
DataLocation dl;
auto s = dl.getRootLocation();
BOOST_CHECK_EQUAL(s, "/home/tc/data/forex" );
BOOST_CHECK_EQUAL(dl.Param2String(DataLocation::period),"PERIOD");
BOOST_CHECK_EQUAL(dl.String2Param("PERIOD"),DataLocation::period);
BOOST_CHECK_THROW(dl.String2Param("SOMETHING"), EDataLocationNotValidParam);
BOOST_CHECK_THROW(dl.Param2String((DataLocation::Params)100), EDataLocationNotValidParam);
}
BOOST_AUTO_TEST_SUITE_END()
C++ is very picky about what it will let you initialize inside of a class definition; there are some particularly non-intuitive rules surrounding static members. It all has to do with the ODR, and why all the rules are the way they are is not especially important.
To cut to the chase, making your array a static constexpr const member should shut the compiler up. With the C++11 standard, the restrictions were relaxed a bit, and one of the new stipulations was that static constexpr members can be initialized inline. This is perfect for your application, since the strings in your array are compile-time constants.
The recent g++ compiler which support C++0x or later compiles thus code. Pure C compile compiles, too. Because strings in initialization like {"MODEL", "PERIOD"}; implemented as const char * pointer to the char array.