I have a class defined as
typedef std::string Name;
typedef int Age;
typedef std::string Level;
class Employee
{
public:
// Employee (arguments);
// virtual ~Employee ();
void name(Name const & name) { name_ = name; }
Name name() const { return name_; }
void age(Age const & age) { age_ = age; }
Age age() const { return age_; }
void level(Level const & level) { level_ = level; }
Level level() const { return level_; }
private:
Name name_;
Age age_;
Level level_;
};
std::vector<Employee> read_file(std::string filename);
std::vector<Employee> employees = read_file("data.txt");
std::cout << employees.size() << std:: endl;
for(std::vector<Employee>::iterator it = employees.begin(); it != employees.end(); ++it)
{
std::cout << *it << std::endl;
}
Is there a way for me to access the members of the class Employee using this vector defined above? I want to construct a map container with level of the employee as the key value.
If you want to access members of Employee from the iterator you can use the member access operator ->:
the_map[it->level()] = blah;
Unless I'm misinterpreting your question, this is simple enough.
it is an iterator over the vector of Employee.
*it is the Employee
it-> lets you access members of that Employee
e.g.: it->name()
So, if you want to build a map of employee level to Employee, you can do this:
std::map<Level, Employee> employeeMap;
for(std::vector<Employee>::iterator it = employees.begin();
it != employees.end();
++it)
{
employeeMap[ it->level() ] = *it;
}
Now you have your employeeMap, which maps the employee's Level to the Employee
const Name name = it->name();
const Age age = it->age();
const Level level = it->level();
or
const Name name = employees[i].name();
const Age age = employees[i].age();
const Level level = employees[i].level();
will work fine.
I would, however, strongly recommend you return each of the above items as references as it will generally be a lot faster than making a copy of the object.
ie
class Employee
{
public:
// Employee (arguments);
// virtual ~Employee ();
void name(Name const & name) { name_ = name; }
Name& name() { return name_; }
const Name& name() const { return name_; }
void age(Age const & age) { age_ = age; }
Age& age() { return age_; }
const Age& age() const { return age_; }
void level(Level const & level) { level_ = level; }
Level& level() { return level_; }
const Level& level() const { return level_; }
private:
Name name_;
Age age_;
Level level_;
};
Then you can access the values by reference as follows:
const Name& name = it->name();
const Age& age = it->age();
const Level& level = it->level();
It also means you can change the values like this:
it->name() = "Goz";
it->age() = 33;
it->level() = "Programmer";
Related
This is the code of the program I have written and everything works just perfectly except the part that it has only one requirement. The ID data member of the class Department should be unique for each instance of that class. I have tried using operator overloading to compare the IDs of the Departments created. But the problem with that would be that the comparison should be made in the main driver of the program, and it is required to be made either in the constructor of the class or inside the class.
Here is the code
class Department {
public:
Department(string id) {
ID = id;
}
bool operator== (const Department& rhs) {
return ID == rhs.ID;
}
friend ostream& operator<<(ostream& out, const Department& value);
protected:
string ID;
};
ostream& operator<<(ostream& out, const Department& value)
{
out << value.ID;
return out;
}
int main() {
Department d1("ID-1");
Department d2("ID-1");
if (d1 == d2) {
cout << "They are the same";
}
else {
cout << "No the same";
}
}
You can make a static attribute that is incremented after each assignment. The static attribute will be the same for all instances.
This may be what the previous answer is intending, though this one increments whenever an object is constructed. That way each object is given essentially a new serial number when it comes to life.
class Department {
public:
Department() {
ID = "ID_" + std::to_string(IDcount);
++IDcount;
}
bool operator== (const Department& rhs) {
return ID == rhs.ID;
}
protected:
string ID;
static int IDcount;
};
int Department::IDcount = 0;
To ensure that no two instances of a class have the same value for a data-member, you can make its constructor non-public and use a singleton friend class to manage its instances.
class Department
{
protected:
string ID;
friend class DepartmentCreator;
Department(string id)
{
ID = id;
}
Department();
};
class DepartmentCreator
{
private:
map<string, Department *> dept_instances;
static DepartmentCreator *this_instance;
DepartmentCreator();
public:
DepartmentCreator(const DepartmentCreator &) = delete;
void operator=(const DepartmentCreator &) = delete;
static DepartmentCreator *GetCreator();
Department *GetDepartment(string id);
};
DepartmentCreator *DepartmentCreator::this_instance = nullptr;
DepartmentCreator::DepartmentCreator() {}
DepartmentCreator *DepartmentCreator::GetCreator()
{
if (!this_instance)
{
this_instance = new DepartmentCreator();
}
return this_instance;
}
Department *DepartmentCreator::GetDepartment(string id)
{
if (dept_instances.find(id) == dept_instances.end())
{
dept_instances[id] = new Department(id);
}
return dept_instances[id];
}
Now, you can use it like this:
DepartmentCreator *dept_creator = DepartmentCreator::GetCreator();
Department *d1 = dept_creator->GetDepartment("ID-1");
Department *d2 = dept_creator->GetDepartment("ID-1");
There is no need to overload ==. You will always get the same pointer for a given ID.
I have a class CPerson and I want to initialize a vector of type CPerson with object variables. However the compiler says that type name is not allowed. I would like to ask why is that?
class CPerson {
protected:
string m_strName;
Sex m_Sex;
Titles m_Title;
public:
CPerson() {
m_strName = "Peter Petrov";
m_Sex = male;
m_Title = bachelor;
}
//добавяме параметричен к-р
CPerson(string n,Sex s,Titles t) {
m_strName = n;
m_Sex = s;
m_Title = t;
}
~CPerson() {}
void SetName(string strName) {
m_strName = strName;
}
void SetSex(Sex sex) {
m_Sex = sex;
}
void SetTitle(Titles title) {
m_Title = title;
}
string GetName() const {
return m_strName;
}
};
int main(){
vector <CPerson> perr = { CPerson p1,
CPerson p2("I.Ivanov", male, professor),
CPerson p3("A.Stoyanova", female, assistant),
CPerson p4("A.Dimitrova", female, assistant)}
return 0;
}
There are a lot of problems in your code. Here is a version of the code that compiles successfully:
// Example program
#include <iostream>
#include <string>
#include <vector>
enum class Sex {
male, female
};
enum class Titles {
bachelor,
assistant,
professor
};
class CPerson {
protected:
std::string m_strName;
Sex m_Sex;
Titles m_Title;
public:
CPerson() {
m_strName = "Peter Petrov";
m_Sex = Sex::male;
m_Title = Titles::bachelor;
}
//добавяме параметричен к-р
CPerson(std::string n,Sex s,Titles t) {
m_strName = n;
m_Sex = s;
m_Title = t;
}
void SetName(std::string strName) {
m_strName = strName;
}
void SetSex(Sex sex) {
m_Sex = sex;
}
void SetTitle(Titles title) {
m_Title = title;
}
std::string GetName() const {
return m_strName;
}
};
int main(){
std::vector <CPerson> perr({
CPerson(),
CPerson("I.Ivanov", Sex::male, Titles::professor),
CPerson("A.Stoyanova", Sex::female, Titles::assistant),
CPerson("A.Dimitrova", Sex::female, Titles::assistant)
});
return 0;
}
Besides the missing types for Sex and Titles, the main problem was in the syntax of your vector initializer. I assume that you were trying to use an initializer list, but your syntax was all wrong. It looks like you were just copying variable declaration / initialization statements into it, but you need to create new instances of your CPerson class. These instances will then be copied into the vector.
CPerson p2("I.Ivanov", male, professor)
Declares and initializes a variable named p2 of class CPerson on the stack, but this syntax is not valid inside an initializer list, since you're not permitted to declare variables there. Instead use
CPerson("I.Ivanov", Sex::male, Titles::professor)
This creates an instance of CPerson, and this instance is then copied into the vector.
I have a class Person that has a name and an age.
I have a container class called people that stores a set of persons.
I have created two custom comparators to sort by name and by age.
When I store the set containing Persons in my class (People) how do pass the custom comparator in.
for Example
My comparator looks like this
struct compareByName
{
bool operator()(const Person & Left, const Person & Right)
{
return (Left.getName() < Right.getName());
}
};
in the main if I want to sort a set of persons by name I just do
set<Person, compareByName> peopleByName;
or for age I do
set<Person, compareByAge> peopleByAge;
Where I am having trouble is How do I use this in my people container class
I would have something like
class People
{
private:
set<Person, COMPARATOR> m_people;
}
where COMPARATOR could either be by name or age
You can use std::function as comparator type and then provide particular comparator for constructor:
class People
{
using PeopleSet = set<Person, std::function<bool(const Person &p1, const Person &p2 )>>;
People() : people( compareByName() ) {}
void sortByAge();
private:
PeopleSet people;
};
note you cannot change comparator after creation of set, you have to create another instance:
void People::sortByAge()
{
people = PeopleSet( people.begin(), people.end(), compareByAge() );
}
and that would involve copying or moving whole set. If you want to be able to use both ways at the same time use boost::multi_index instead.
You can do it via template:
#include <iostream>
#include <string>
#include <set>
class Person
{
private:
std::string name;
int age;
public:
Person(std::string name, int age) : name(name), age(age) {};
std::string getName() const { return name; };
int getAge() const { return age; };
};
template<class COMPARATOR> class People
{
private:
std::set<Person, COMPARATOR> m_people;
public:
void AddPerson(Person const &p)
{
m_people.insert(p);
}
void PrintPeople()
{
for (Person p : m_people)
{
std::cout << p.getName() << " - " << p.getAge() << std::endl;
}
}
};
struct SortedByName
{
bool operator()(const Person & Left, const Person & Right)
{
return (Left.getName() < Right.getName());
}
};
struct SortedByAge
{
bool operator()(const Person & Left, const Person & Right)
{
return (Left.getAge() < Right.getAge());
}
};
int main()
{
Person p1("Bob", 21);
Person p2("Jack", 13);
Person p3("Kath", 33);
People<SortedByName> ppl1;
ppl1.AddPerson(p1);
ppl1.AddPerson(p2);
ppl1.AddPerson(p3);
std::cout << "By Name:" << std::endl;
ppl1.PrintPeople();
std::cout << std::endl;
People<SortedByAge> ppl2;
ppl2.AddPerson(p1);
ppl2.AddPerson(p2);
ppl2.AddPerson(p3);
std::cout << "By Age:" << std::endl;
ppl2.PrintPeople();
return 0;
}
Prints:
By Name:
Bob - 21
Jack - 13
Kath - 33
By Age:
Jack - 13
Bob - 21
Kath - 33
I'm trying to create a named-arguments-like constructor for some of the classes of a project.
The way I'm doing it is by defining a class proxy which will hold the arguments and pass an instance of this proxy to the constructor of my classes.
Everything worked fine until I had to derive one of my classes.
Basically I thought: I'm gonna derive the new derived class proxy from the base class proxy. This works too, but only if I use only the derived proxy class arguments.
Here is an example since it is easier to understand:
class Person
{
public:
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
}
public:
Person()
: _name("")
, _surname("")
{ }
Person(const PersonArgs& args)
: _name(args.Name())
, _surname(args.Surname())
{ }
protected:
std::string _name;
std::string _surname;
}
class PersonEx : public Person
{
public:
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
}
public:
PersonEx()
: _address("")
{ }
PersonEx(const PersonExArgs& args)
: Person(args)
, _address(args.Address())
{ }
protected:
std::string _address;
}
int main(int argc, char** argv)
{
// This is ok since PersonExArgs::Address returns a PersonExArgs&
PersonEx* p1 = new PersonEx(PersonEx::PersonExArgs().Address("example"));
// This won't work since PersonExArgs::Name returns a PersonArgs&
PersonEx* p2 = new PersonEx(PersonEx::PersonExArgs().Address("example").Name("Mark"));
}
Basically, since I chain the arguments returning a reference to the proxy class instance when I set an argument, it breaks when using this from a derived proxy class since it will return a reference to the base proxy class and not the derived one, not allowing me to access the derived proxy arguments and neither pass it to the constructor of the derived class.
Anyone has an idea on how to fix this?
Maybe covariant return types are what you are looking for.
See here for more details.
You can define PersonArgs as (note virtual keywords placed around):
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
virtual PersonArgs& Name(const std::string& name)
{
_name = name;
return *this;
}
const std::string& Surname() const { return _surname; }
virtual PersonArgs& Surname(const std::string& surname)
{
_surname = surname;
return *this;
}
protected:
std::string _name;
std::string _surname;
};
Then define PersonExArgs as (note override and the covariant return type):
class PersonExArgs : public Person::PersonArgs
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
PersonExArgs& Name(const std::string& name) override
{
PersonArgs::Name(name);
return *this;
}
PersonExArgs& Surname(const std::string& surname) override
{
PersonArgs::Surname(surname);
return *this;
}
protected:
std::string _address;
};
Probably it's annoying for you have to override each and every function in the base class but it does the work nicely.
See it up and running on wandbox.
The most common solution to this problem is the Curiously Recurring Template Pattern (CRTP):
template <typename Derived>
class PersonArgs
{
public:
const std::string& Name() const { return _name; }
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
const std::string& Surname() const { return _surname; }
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
protected:
std::string _name;
std::string _surname;
};
...
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
public:
const std::string& Address() const { return _address; }
PersonExArgs& Address(const std::string& address)
{
_address = address;
return *this;
}
protected:
std::string _address;
};
In your case, you could combine it with another base class to clean up the interface:
class Person {
class PersonArgsBase
{
public:
const std::string& Name() const { return _name; }
const std::string& Surname() const { return _surname; }
protected:
std::string _name;
std::string _surname;
};
template <typename Derived>
class PersonArgs : public PersonArgsBase
{
Derived& Name(const std::string& name)
{
_name = name;
return static_cast<Derived&>(*this);
}
Derived& Surname(const std::string& surname)
{
_surname = surname;
return static_cast<Derived&>(*this);
}
};
...
};
class PersonEx {
class PersonExArgs : public Person::PersonArgs<PersonExArgs>
{
...
};
};
My problem is just i dont know what to paste where i writed HELP_HERE(see the code above class Dog in function bool operator==) in order to get he comparation between the type Animal of two Dogs. Each dog is an Animal so i need to be able to return the variable that represents "the animal inside the dog". In java i could just use super() and it works what do i need in c++?
`
#include "Animal.h"
class Dog : public Animal
{
private:
char _name;
int _age;
int _hps;
float _peso; // peso is Weight
public:
Dog(char name,int age, float peso, int hps) : Animal(name,age),_peso(peso),_hps(hps) {}
void roar(std::ostream &os) const {
os << "O cao " << _name << " esta a ladrar\n.";
}
int Vidas() const {
return _hps;
}
float Peso() const {
return _peso;
}
int returnAnimal() {
return animal.Age();
}
bool operator==(const Dog &dog) {
return HELP_HERE.operator==(dog.HELP_HERE) &&
dog.Vidas() == _hps && dog.Peso() == _peso;
}
friend std::ostream &operator<<(std::ostream &os, const Dog &dog) {
dog.roar(os);
return os;
}
};`
Class Animal:
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal {
int _age;
char _name;
public:
Animal(int age) : _age(age),_name('-') {}
Animal(int age, char name) : _age(age), _name(name) {}
int Age() const { return _age; }
char Name() const { return _name; }
friend std::ostream &operator<<(std::ostream &os, const Animal &animal) {
animal.sleep(os);
return os;
}
void sleep(std::ostream &os) const {
os << "the animal " << Name() << " is sleeping.\n";
}
void Age(int age) { _age = age; }
bool operator==(const Animal &animal) {
return _age == animal.Age() && _name == animal.Name();
}
};
#endif // ANIMAL_H
Change HELP_HERE.operator==(dog.HELP_HERE) to:
Animal::operator==(dog)
In general you can get an Animal reference with: Animal &a = *this; . C++ doesn't have a keyword which indicates "the parent class", however you can always make your child class contain typedef Animal super; and then you can use super::operator==, or super &a = *this; etc.