Initialize a const field in constructor but first check one parameter - c++

Alright, so this was a task I had on my test.
You need to create a class User with a const int userID so that each User object will have an unique ID.
I was asked to overload the constructor with 2 parameters: key, name. If the key was 0 then the User will have an unique ID, else the user will get userID = -1.
I've done this:
class User{
private:
static int nbUsers;
const int userID;
char* name;
public:
User(int key, char* name) :userID(nbUsers++){
if (name != NULL){
this->name = new char[strlen(name) + 1];
strcpy(this->name);
}
}
};
I don't know how to firstly check if the key parameter is 0 and then initialize the const userID.
Any thoughts?

You can use the ternary operator, so that it can be called directly in the constructor initialization list:
class User
{
private:
static int nbUsers;
const int userID;
char* name;
public:
User(int key, char* name) : userID(key == 0 ? -1 : nbUsers++)
{
// ...
}
};
The standard guarantees that only one of the branches will be evaluated, so nbUsers won't be incremented if key == 0.
Alternatively, you can use a helper function:
int initDependingOnKey(int key, int& nbUsers)
{
if(key == 0) return -1;
return nbUsers++;
}
class User
{
private:
static int nbUsers;
const int userID;
char* name;
public:
User(int key, char* name) : userID(initDependingOnKey(key, nbUsers))
{
// ...
}
};

Related

Is it ideal to put data inside a private class? (C++)

For example, I have this class:
struct bankingFunctionality
{
private:
class bankingData
{
public:
int phoneNum, citizenNum, age, ID;
string name, address;
bankingData* next = nullptr;
};
public:
void input(bankingData*);
void firstUser();
void update(bankingData*);
};
Is it ideal to put the data class in private to "protect" data? Since the only way, I can think of how to access it for input and output is to have functions like void input(...) in public. However, every time I want to call input I would need to create a new object and waste memory.
If you're using this as a way to pass in arguments it's really wasteful and you should consider the traditional getX() and setX() approach for accessors and mutators. You can make these easy to use in a chain style if you return *this at the end of each.
As in:
class bankingData {
int phoneNum, citizenNum, age, ID;
string name, address;
bankingData* next = nullptr;
int getPhoneNum() const { return phoneNum; };
bankingData& setPhoneNum(int n) { phoneNum = n; return *this; };
const std::string& getName() const { return name; };
bankingData& setName(const std::string& n) { name = n; return *this; };
};
Where you can then do:
bankingData bd;
bd.setPhoneNum(111).setName(...);

Pointer tho another Object

I have a little problem .. I want to do car registration and i want to have owner(pointer to a Person object) but when i want to take the owner with get function i can't do that ... and this is mystery for me ... Maybe i have a little mistake somewhere and i can't find it .. Please help :)
class Person
{
friend class Cars;
public:
Person(){}
Person(uint8_t age, string name) :m_age(age), m_name(name)
{
m_idGener = s_idGenerator++;
}
int getId()
{
return m_idGener;
}
uint8_t getAge()
{
return m_age;
}
string getName()
{
return m_name;
}
private:
string m_name;
uint8_t m_age;
static int s_idGenerator;
int m_idGener;
};
class Cars:public Person
{
public:
Person *m_owner; // this is my pointer which i want to point to cars Object
it will stay public for the test after the test i will move it in the private section
Cars()
{
}
// getters and setters
Cars setOwner(Cars &object, Person &owner) // with this function i set the owner
{
object.m_owner = &owner;
}
Cars getOwner(Cars &object) /// here is my problem i can't take the owner
{
return *(object.m_owner); // but i can't take the owner
}
uint16_t getHorsePower()
{
return horsePower;
}
string getRegNumber()
{
return registrationNumber;
}
private:
string m_manufacturerName;
string modelName;
uint16_t horsePower;
string registrationNumber;
};
int Person::s_idGenerator = 0;
You have made more mistakes. At least the followings should be corrected:
Cars setOwner(Cars &object, .....
This method doest not return a value, so it should be void. The car object should be the object for which the method will be called, not a parameter.
Cars getOwner(Cars &object) /// here is my problem i can't take the owner
{
return *(object.m_owner); // but i can't take the owner
}
In this method I would change the return type to Person *, then return simply m_owner. Parameter is not needed.
A modified working example:
#include <string>
#include <iostream>
using namespace std;
class Person
{
friend class Cars;
public:
Person(){}
Person(uint8_t age, string name) :m_age(age), m_name(name)
{
m_idGener = s_idGenerator++;
}
int getId()
{
return m_idGener;
}
uint8_t getAge()
{
return m_age;
}
string getName()
{
return m_name;
}
private:
string m_name;
uint8_t m_age;
static int s_idGenerator;
int m_idGener;
};
class Cars:public Person
{
public:
Person *m_owner; // this is my pointer which i want to point to cars Object
// it will stay public for the test after the test i will move it in the private section
Cars()
{
}
// getters and setters
void setOwner(Person &owner) // with this function i set the owner
{
m_owner = &owner;
}
Person *getOwner() /// here is my problem i can't take the owner
{
return (m_owner); // but i can't take the owner
}
uint16_t getHorsePower()
{
return horsePower;
}
string getRegNumber()
{
return registrationNumber;
}
private:
string m_manufacturerName;
string modelName;
uint16_t horsePower;
string registrationNumber;
};
int Person::s_idGenerator = 0;
int main() {
Person p(5,"Bill");
Cars c;
c.setOwner(p);
cout << c.getOwner()->getName();
}
Here:
Cars setOwner(Cars &object, Person &owner) // with this function i set the owner
{
object.m_owner = &owner;
}
You declared out value type as "Cars" but you don't return anything.
And here:
Cars getOwner(Cars &object) /// here is my problem i can't take the owner
{
return *(object.m_owner); // but i can't take the owner
}
You want to return "Person" object but again you declared out value type as "Cars".
So you can change this functions like that:
First:
void setOwner(Cars &object, Person &owner);
Second:
Person getOwner(Cars &object);

C++ Pass a argument through a class with array index?

class cat
{public:
void dog(int ID, char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
}
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
I want something similar to this.
include <vector>
class CatArray;
class Cat {
// This line means that the CatArray class can
// access the private members of this class.
friend class CatArray;
private:
static int ID;
public:
void dog(const char* value) {
// Use ID here any way you want.
}
};
int Cat::ID = 0;
class CatArray {
private:
std::vector<Cat> cats;
public:
explicit CatArray(unsigned int size) : cats(size) {}
Cat& operator [](unsigned int index) {
Cat::ID = index;
return cats[index];
}
};
But a little different. There are 18 Clients in a game and i need to basically do this. for eg, "Client 4 Chooses an option and the option gets called through the array index and than that way client 4 will call the function with the function holding the index 4"
Then cats[1] is not really a Cat object but a CatWithIndex object:
class Cat {
public:
void dog(size_t index,const char* value);
};
class CatWithIndex {
size_t index_;
const Cat &cat_;
public:
CatWithIndex(size_t index, const Cat &cat): index_(index), cat_(cat) {}
void dog(const char* value) {
cat_.dog(index_,value);
}
};
class CatArray {
private:
std::vector<Cat> cats;
public:
Cat& operator [](unsigned int index) {
Cat::ID = index;
return CatWithIndex(index,cats[index]);
}
};

C++ Pass a argument through a class with array index

Is there anyway I can pass a argument through a class like below for example.
class cat
{
public:
void dog(int ID, const char *value) // int ID I'd like to be the index array it was called from?
{
debug(ID, value);
}
};
cat cats[18];
cats[1].dog("value second arg, first arg auto filled from index array");
How about something like this:
class cat
{
public:
void dog(const char *value)
{
//debug(ID, value);
}
};
cat cats[18];
void cat_dog(int ID, const char *value)
{
debug(ID, value);
cats[ID].dog(value);
}
//cats[1].dog("value second arg, first arg auto filled from index array");
cat_dog(1, "value second arg, first arg auto filled from index array");
As mentioned in comment, you may alternatively use a member to store the index, and then no need to provide it in successive calls:
class cat
{
public:
cat(int index) : index(index) {}
void dog(const char *value) { debug(index, value); }
private:
std::size_t index;
};
And then initialize the array:
std::vector<cat> cats;
for (std::size_t i = 0; i != 18; ++i) {
cats.push_back(cat(i));
}
And then call any method:
cats[1].dog("text value, index 1 already stored in object");

expecting primary expression before token in c++

Here is the problem:
In console.cpp
void Console::PrintMedicine(Medicine* m){
int ID = Medicine.getID(); //here i get the error expecting primary expression before "." token, it doesn't work with -> either
cout<<"The Medicine's ID is: ";
cin>>ID;
}
class Medicine:
what's private:
private:
int ID;
std::string nume;
double concentratie;
int cantitate;
what's public
public:
Medicine(); //implcit constructor
Medicine(int ID, std::string nume, double concentratie, int cantitate);//constructor with parameteres
~Medicine(); //destructor
//the getID function
const int& Medicine::getID() const{
return this->ID;
}
//the getName function
const std::string& Medicine::getName() const{
return this->nume;
}
//the getConcentration function
const double& Medicine::getConcentration() const{
return this->concentratie;
}
//the getQuantity function
const int& Medicine::getQuantity() const{
return this->cantitate;
}
The expression Medicine.getID() is incorrect. Medicine is the name of a class, and you can't use the dot operator to access its members. First, you need an instance of Medicine whose members you want to access; second, if you have a pointer to that instance, you need to use the arrow operator (operator ->).
Therefore, it should be:
void Console::PrintMedicine(Medicine* m){
int ID = m->getID();
// ^^^
// ...
}