How should I implement a static collection of Strings in my class - c++

I am very new to C++ so this might be an easy question to answer. I am writing a class (Person) and when a Person is created it should be assigned a random name from a collection of predefined names. So within the Person class I would like to define some sort of static collection of strings that I can access randomly and therefore I would also need to know how many there are.
I am using Qt here too, so the solution should preferably be using things from the standard library or the Qt library.
I am from a Java background and in Java I would probably do something like:
private static final String[] NAMES = { "A", "B" };
What would be the equivalent in this case?

You could use QStringList.
Person.h:
class Person
{
private:
static QStringList names;
};
Person.cpp:
QStringList Person::names = QStringList() << "Arial" << "Helvetica"
<< "Times" << "Courier";

Assuming C++03:
class YourClass {
static const char*const names[];
static const size_t namesSize;
};
// in one of the translation units (*.cpp)
const char*const YourClass::names[] = {"A", "B"};
const size_t YourClass::namesSize = sizeof(YourClass::names) / sizeof(YourClass::names[0]);
Assuming C++0x:
class YourClass {
static const std::vector<const char*> names;
};
// in one of the translation units (*.cpp)
const vector<const char*> YourClass::names = {"A", "B"};
And of course you can use your favorite string type instead of const char*.

First, a very simple program for generating random names from a static array. The proper class implementation can be found further down.
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
// import the std namespace (to avoid having to use std:: everywhere)
using namespace std;
// create a constant array of strings
static string const names[] = { "James", "Morrison",
"Weatherby", "George", "Dupree" };
// determine the number of names in the array
static int const num_names = sizeof(names)/sizeof(names[0]);
// declare the getRandomName() function
string getRandomName();
// standard main function
int main (int argc, char * argv[])
{
// seed the random number generator
srand(time(0));
// pick a random name and print it
cout << getRandomName() << endl;
// return 0 (no error)
return 0;
}
// define the getRandomName() function
string getRandomName()
{
// pick a random name (% is the modulo operator)
return names[rand()%num_names];
}
Class implementation
Person.h
#ifndef PERSON_
#define PERSON_
#include <string>
class Person
{
private:
std::string p_name;
public:
Person();
std::string name();
};
#endif
Person.cpp
#include "Person.h"
#include <stdlib.h>
using namespace std;
static string const names[] = { "James", "Morrison",
"Weatherby", "George", "Dupree" };
static int const num_names = sizeof(names)/sizeof(names[0]);
Person::Person() : p_name(names[rand()%num_names]) { }
string Person::name() { return p_name; }
main.cpp
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
#include "Person.h"
using namespace std;
int main (int argc, char * argv[])
{
// seed the random number generator
srand(time(0));
// create 3 Person instances
Person p1, p2, p3;
// print their names
cout << p1.name() << endl;
cout << p2.name() << endl;
cout << p3.name() << endl;
// return 0 (no error)
return 0;
}

Related

anyone know how to initialize an empty array

Anyone know how to Initialise the array of car registration structures by placing a “Empty” in the car registration number of each array element.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car;
{
string car_reg = 0;
char car_manuf[30];
char car_model[30];
double price;
string car_reg{};
}
}
need some h3elp
Explanation inline.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car // removed ; the ; terminates the definition, cutting it off
// and leaving you with a declaration. Everything in the braces
// that follow would be seen as a block of code defining two
// automatic variables scoped inside the block. Useless in this
// case.
{
string car_reg = 0; // this is actually NASTY! More on it later
char car_manuf[30] = "EMPTY"; // assigns default value. But only if your
// compiler comes from this decade.
// If you are rocking an antique you can't
// do this. Will cover what you can do below.
char car_model[30] = "EMPTY";
string car_reg{}; // cannot reuse the car_reg identifier in the same scope
// car_reg is either a variable or a function.
}; // ; goes here
car c; // for testing purposes
cout << c.car_manuf << ',' << c.car_model; // for testing
}
string car_reg = 0; is nasty. What it does is defines a member variable car_reg and uses 0 as the default. The 0 is converted to a null pointer to a char array. The string constructor attempts to initialize from a null pointer and blows up at runtime. The compiler is just fine with this bit of stupidity because in the old days NULL could be #define NULL 0 and we don't want to break decades of old code by fixing this problem.
Since we can't do default initializations in pre C++11 code we need a constructor to do the work. Yup. structs can have constructors. This is because a struct and a class are almost identical. The only difference you're ever likely to see between the two is class defaults to private access and structs default to public access.
struct car
{
char car_manuf[30];
char car_model[30];
car (): car_manuf("EMPTY"), car_model("EMPTY")
{
}
};
Note that his isn't as groovy as it looks. You're usually better off with something like
struct car
{
string car_manuf;
string car_model;
car (const string & manuf,
const string & model): car_manuf(manuf), car_model(model)
{
}
};
and not allowing the empty case at all. When possible force users to initialize a class into a fully initialized state. And use std::string. Very handy tool, std::string.
Note that
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model):
car_manuf(manuf), car_model(model) // fails to compile
{
}
};
is not possible. You can't initialize a char array with a pointer to char. I'm not entirely certain why the language doesn't have a rule to handle this, but it doesn't. If forced to use char arrays,
struct car
{
char car_manuf[30];
char car_model[30];
car (const char * manuf,
const char * model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
and make dang sure that manuf and model will fit in 29 characters or less.
Have you tried a simple for loop, to fill (for example) the char_model array with zeros?
....
char car_model[30];
/* Adding the for loop here (it will fill car_model's elements with zeros*/
for(int i=0; i<=sizeof(car_model); i++){
car_model[i]=0;
....
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <conio.h>
#include <iomanip>
using namespace std;
int main()
{
struct car
{
string car_reg = {"Empty"};
char car_manuf[30];
char car_model[30];
car(const char* manuf,
const char* model)
{
strcpy(car_manuf, manuf);
strcpy(car_model, model);
}
};
}

How to get the name of an Object

I am coding a little RPG(Role Playing Game)
Here is the situation: I created an object Personnage.
In my classes, I created a method atttaquer. But I would like that after calling my method attaquer it writes something like this: Goliath attaque David . But to that, I need to grab the name of the Object. Because the player may want to edit the name of Object (The personage name) before playing.
There is my code:
Personnage.h
#ifndef Personnage_h
#define Personnage_h
#include <string>
#include "Arme.h"
class Personnage{
//methods
public:
Personnage();
Personnage(std::string nomArme, int degatsArme);
Personnage(int vie, int mana);
// ~Personnage();
void recevoirDegats(int nbDegats);
void attaquer(Personnage &cible);
private:
// Attributs
int m_vie;
int m_magie;
std::string m_nom;
};
#endif
My Personnage.cpp code:
#include "Personnage.h"
#include <string>
#include <iostream>
void Personnage::recevoirDegats(int nbDegats){
m_vie -= nbDegats;
if (m_vie < 0) {
m_vie = 0;
}
}
void Personnage::attaquer(Personnage &cible){
cible.recevoirDegats(m_arme.getDegats());
// if David attacks Goliath I want to write std::cout << David << "attaque "<< Goliath << endl; but I do not know how to grab the name of the object after it's creation
}
There is my main.cpp
#include <iostream>
#include <string>
#include "Personnage.h"
//#include "Personnage.cpp"
#include <ctime>
using namespace std;
int main()
{
Personnage David, Goliath, Atangana("Ak47", 35);
Goliath.attaquer(David);
return 0;
}
If you want to give your objects names, it cannot be the variable names. They are only meant for the compiler and they are fixed. So you need to create a class that can have a name:
class NamedObject
{
private:
std::string m_name;
public:
const std::string& getName() const
{
return m_name;
}
void setName(const std::string& name)
{
m_name = name;
}
}
And if you want your classes to have a name, the easiest way would be to derive from it:
class Personnage : NamedObject {
Then you can say:
Personnage player1, player2;
player1.setName("David");
player2.setName("Goliath");
Alternatively, you can get those string from user input.
And if you need to address one by name:
std::cout << player1.getName() << " please make your move." << std::endl;

c++ recursive class dependencies

I'm trying to make something similar to std::Map. I have two classes, NameValue which takes a name and a Value. The class Value can hold data of type int and string. I want the Value class to also accept NameValue to be able to create nested objects. Currently the boost::variant is used to hold the data types allowed to be used.
NameValue.h
#ifndef INC_NAME_VALUE_H_
#define INC_NAME_VALUE_H_
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include "value.h"
namespace config {
using namespace std;
class Value; // forward declaration
class NameValue {
private:
string name;
Value* valuePtr;
public:
NameValue(){};
NameValue(string name, Value& value)
: name(name)
, valuePtr(&value){};
void Print() {
cout << name << " : ";
// valuePtr->Print();
}
void Set(Value* value) { valuePtr = value; }
};
}
#endif /* INC_NAME_VALUE_H_ */
Value.h
#ifndef INC_VALUE_H_
#define INC_VALUE_H_
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include "name_value.h"
namespace config {
using namespace std;
using variantDataType = boost::variant<int, string>;
class Value {
private:
variantDataType value;
public:
Value(){};
Value(variantDataType const& value)
: value(value){};
void Print() { cout << value << endl; }
};
}
#endif /* INC_VALUE_H_ */
In Value.h I want to add NameValue to variant like this:
boost::variant<int,string,NameValue> value;
main.cpp
Value i(42);
NameValue nv("meaning", i);
NameValue nv2("nested, NameValue("deep", "value"));//this is what I want
Maybe I'm on the wrong track using variant or the way I'm using dependencies. If there is some other way to make it work I would appreciate the suggestions.

C++ managing ifstream in a container with different object types

I have created several different objects of Dog and Cat inside the container animalColl. I am trying to workout how to adjust the file stream that is read so that if the object in the container is Cat then the catfile is used and Dog uses the dogfile. Currently, only the animalType passed into the parameter is used. Is it possible to choose which file stream is used based on the object type?
void Animal::load(std::string animalType)
{
std::string file = animalType + ".csv";
std::ifstream lstream(file);
for (Animal *a : animalColl)
{
a->load(lstream); //uses one stream to read all the different objects in container
}
}
Unfortunately, I'm not sure why you're calling load recursively, so I can't give an exact answer. I think the answer you're looking for is going to be using polymorphism. This is a basic example:
animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
#include <string>
class Animal
{
public:
void load()
{
std::string fileName = this->getAnimalFilename() + ".csv";
std::cout << "fileName = " << fileName << std::endl;
}
protected:
virtual std::string getAnimalFilename() { return "Animal"; }
};
#endif //ANIMAL_H
dog.h
#ifndef DOG_H
#define DOG_H
#include <string>
#include <iostream>
class Dog : public Animal
{
protected:
virtual std::string getAnimalFilename() { return "Dog"; }
};
#endif //DOG_H
cat.h
#ifndef CAT_H
#define CAT_H
#include <iostream>
#include <string>
class Cat : public Animal
{
protected:
virtual std::string getAnimalFilename() { return "Cat"; }
};
#endif //CAT_H
And an example usage (note that you MUST use a pointer to the base class to get the overriding feature of polymorphism, and you MUST declare a function as virtual to override it in the derived class).
EDIT: The below main.cpp was edited to use smart pointers because it used raw pointers and caused a memory leak, pointed out by #ArchbishopOfBanterbury.
main.cpp
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include "animal.h"
#include "dog.h"
#include "cat.h"
int main(int argc, char *argv[])
{
std::vector<std::unique_ptr<Animal>> animalColl;
animalColl.emplace_back(new Dog());
animalColl.emplace_back(new Cat());
animalColl.emplace_back(new Cat());
animalColl.emplace_back(new Dog());
for (auto &a : animalColl) {
a->load();
}
return 0;
}
And the output:
fileName = Dog.csv
fileName = Cat.csv
fileName = Cat.csv
fileName = Dog.csv
The basic idea is that you use the keyword virtual to override the behavior when using a pointer to the base class. So in my example, getAnimalFilename is overrided in the Dog and Cat class to return the correct string, rather than passing it into the load() function. Does that help any? Go ahead and reply to this comment and I'll try to help as much as I can.
There are a few ways you could do this. You could add an element to the class called name and strcmp this to check for type for instance:
struct Animal {
};
struct Dog : Animal {
string name = "Dog";
};
struct Cat : Animal {
string name = "Cat";
};
int main() {
Dog d;
if("Dog" == d.name) {
//do something
}
else if("Cat" == d.name) {
//do something else
}
}
Another way to do this would be if you know the type of another object, or are willing to create another object of type Dog or Cat, you can compare those types using typeid(obj) for instance, using the same structs as above:
int main(int argc, const char * argv[]) {
Dog d, o;
if (typeid(d) == typeid(o)) {
//do something
}
else {
//do something else
}
}

passing struct parameter by reference c++

how can i pass a struct parameter by reference c++, please see below the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
struct TEST
{
char arr[20];
int var;
};
void foo(char * arr){
arr = "baby"; /* here need to set the test.char = "baby" */
}
int main () {
TEST test;
/* here need to pass specific struct parameters, not the entire struct */
foo(test.arr);
cout << test.arr <<endl;
}
The desired output should be baby.
I would use std::string instead of c arrays in c++
So the code would look like this;
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;
struct TEST
{
std::string arr;
int var;
};
void foo(std::string& str){
str = "baby"; /* here need to set the test.char = "baby" */
}
int main () {
TEST test;
/* here need to pass specific struct parameters, not the entire struct */
foo(test.arr);
cout << test.arr <<endl;
}
That's not how you want to assign to arr.
It's a character buffer, so you should copy characters to it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
struct TEST
{
char arr[20];
int var;
};
void foo(char * arr){
strncpy(arr, "Goodbye,", 8);
}
int main ()
{
TEST test;
strcpy(test.arr, "Hello, world");
cout << "before: " << test.arr << endl;
foo(test.arr);
cout << "after: " << test.arr << endl;
}
http://codepad.org/2Sswt55g
It looks like you are using C-strings. In C++, you should probably look into using std::string. In any case, this example is passed a char array. So in order to set baby, you will need to do it one character at a time (don't forget \0 at the end for C-strings) or look into strncpy().
So rather than arr = "baby" try strncpy(arr, "baby", strlen("baby"))
It won't work for you beause of the reasons above, but you can pass as reference by adding a & to the right of the type. Even if we correct him at least we should answer the question. And it wont work for you because arrays are implicitly converted into pointers, but they are r-value, and cannot be converted into reference.
void foo(char * & arr);