Baza danych pracowników - pomoc z zaktualizowaniem bazy

0

Kod main:

#include "maptemplate.h"

int main(void)
{
    typedef unsigned int ID;                            //Identification number of Employee
    map_template<ID,Employee> Database;                 //Database of employees

    Database.Add(761028073,Employee("Jan Kowalski","salesman",28));     //Add first employee: name: Jan Kowalski, position: salseman, age: 28,
    Database.Add(510212881,Employee("Adam Nowak","storekeeper",54));    //Add second employee: name: Adam Nowak, position: storekeeper, age: 54
    Database.Add(730505129,Employee("Anna Zaradna","secretary",32));    //Add third employee: name: Anna Zaradna, position: secretary, age: 32
	
    cout << Database << endl;                         //Print databese

    map_template<ID,Employee> NewDatabase = Database; //Make a copy of database

    Employee* pE;
    pE = Database.Find(510212881);       //Find employee using its ID
    pE->Position = "salesman";          //Modify the position of employee
    pE = Database.Find(761028073);     //Find employee using its ID
    pE->Age = 29;             //Modify the age of employee

    Database = NewDatabase;    //Update original database
 
    cout << Database << endl;  //Print original database
cout<<"Wszystko dziala"<<endl;
}

kod .h:

#include <iostream>
#include <vector>

using namespace std;

 template <class Key, class T> class map_template; 
 template <class Key, class T> ostream& operator<< (ostream &o,const map_template<Key, T> &map);
template <class Key, class T> //template <klucze, dane pracownikow>
class map_template{ 
private:
    vector<Key> keys;   //vector do przechowywania unikalnych kluczy pracowników
    vector<T> content;  //vector do przechowywania danych pracowników
public:

    map_template(){}
    void Add(Key key, T t);
    T* Find(Key key);
friend ostream& operator<< <>(ostream &out,const map_template<Key, T> &map);
}; //koniec klasy map_template

//Dodanie do bazy (Add)
template<class Key, class T>
void map_template <Key, T>::Add(Key key, T t)
{
    keys.push_back(key);
    content.push_back(t);
}
//Szukanie w bazie (Find)
template<class Key, class T>
T* map_template<Key, T>::Find(Key key)
{
    for(unsigned int i = 0; i < keys.size(); i++)
        if (keys[i] == key)
        {
            return &content.at(i);
        }
return nullptr;
}

//Początek klasy Employee bez template
class Employee
{
private:

public:
    Employee(string Name, string Position, int Age);
    string Name;
    int Age;
    string Position;

};//koniec klasy employee

//Dodanie pól Name, Age, Position
Employee::Employee(string Name, string Position, int Age)
{
    this->Name = Name;
    this->Age = Age;
    this->Position = Position;

}
//operator <<
template<class Key, class T>
ostream& operator<<(ostream &out,const map_template<Key, T> &map)
{
	for(unsigned int i=0;i<map.content.size();i++)
	{
		out << map.keys[i] <<", " << map.content[i].Name << ", " <<map.content[i].Position << ", " <<map.content[i].Age <<endl;
	}
return out;
}

Potrzebuję dorobić kod aktualizujący bazę danych:

map_template<ID,Employee> NewDatabase = Database; //Make a copy of database
// (...)
Database = NewDatabase;
1

Słowa klucze - konstruktor kopiujący oraz operator=
EDIT:
W sumie, skoro to C++11 to jeszcze kolejne słowo klucz - konstruktor przenoszący.

0

No ok.
Czyli zrobię konstruktor kopiujący, a potem w kodzie operatora= dam po prostu wywołanie tego konstruktora kopiującego żeby się dane skopiowały? Dobrze rozumiem? :D

I pytanka:

  1. konstruktor kopiujący jak widzę robi się dla danej klasy. Ja mam dwie klasy - Employee i map_template. Będę chciał skopiować dane z wektorów w map_template więc w środku tej klasy mam dodać konstruktor kopiujący (Albo oczywiście dać samą deklarację, a definicję poniżej wszystkiego) czy coś w Employee też bym musiał zrobić?

  2. konstruktor kopiujący jak widziałem robi się zwykle tak, że jest klasa "Test", a nagłówek konstruktora to Test (const Test &test)
    Jest jakiś powód dla którego konstruktor kopiujący ma tą nazwę referencji zapisaną małymi literami czy po prostu robi się to tak żeby się nie pogubić?
    Pytam, bo u nas map_template jest zapisane małymi literami i nie wiem czy mogę dać nagłówek: map_template (const map_template &Map_template) czy jakoś inaczej to zapisać? Bo to by przeczyło zasadzie wtedy. To może powinienem map_template w całym kodzie zamienić na Map_template żeby potem w konstruktorze kopiującym ładnie dać &map_template ?

  3. uuu konstruktor przenoszący ;D Tego to chyba nawet na wykładach u nas nie było :D

1

Całkiem dobrze zaczynasz kombinować.
ad 1) Dobrze kombinujesz, nie wiem tego wprawdzie z góry, ale może się okazać, że kopiowanie klasy map_template przy pomocy konstruktora kopiującego i operatora przypisania wymusi ich definicję także dla klasy Employee.

ad 2) Nie, to po prostu nazwa jak każda inna. Ja osobiście stosuję nazwę orginal albo other, ale nie ma to specjalnego znaczenia. W nazewnictwie tej zmiennej będącej nienaruszalną bazą do skopiowania kieruj się przejrzystością - abyś widząc ją na pierwszy rzut oka miał skojarzenie "to jest oryginalny obiekt z na podstawie którego chcę zrobić kopię, a jego samego nie zepsuć zmieniając w nim coś"

Nazwa map_template istotnie jest zła. Pamiętasz jeszcze lekcję o camelCase? :]
Aby klasa mapy nazywała się jak Swaróg przykazał winna brzmieć MapTemplate, albo po prostu Map (to ostatnie może się gryźć z std::Map)

ad 3)
To sobie chwilowo odpuść, dopiero jak dopytasz profesora czy tak to ma działać to się wróci do tematu.

0
wiezaawieza napisał(a):

No ok.
Czyli zrobię konstruktor kopiujący, a potem w kodzie operatora= dam po prostu wywołanie tego konstruktora kopiującego żeby się dane skopiowały?

No to jest zły pomysł, napisz operator= bez takich kombinacji

0

Tutaj są zasady dotyczące tworzenia konstruktorów:
https://en.cppreference.com/w/cpp/language/rule_of_three

0

Cały kod main:

#include "maptemplate.h"

int main(void)
{
    typedef unsigned int ID;                            //Identification number of Employee
    MapTemplate<ID,Employee> Database;                 //Database of employees
    
    Database.Add(761028073,Employee("Jan Kowalski","salesman",28));     //Add first employee: name: Jan Kowalski, position: salseman, age: 28,
    Database.Add(510212881,Employee("Adam Nowak","storekeeper",54));    //Add second employee: name: Adam Nowak, position: storekeeper, age: 54
    Database.Add(730505129,Employee("Anna Zaradna","secretary",32));    //Add third employee: name: Anna Zaradna, position: secretary, age: 32
	
    cout << Database << endl;                         //Print databese

    MapTemplate<ID,Employee> NewDatabase = Database; //Make a copy of database

    Employee* pE;

    pE = NewDatabase.Find(510212881);       //Find employee using its ID
    pE->Position = "salesman";          //Modify the position of employee
    pE = NewDatabase.Find(761028073);     //Find employee using its ID
    pE->Age = 29;             //Modify the age of employee

    Database = NewDatabase;    //Update original database
 
    cout << Database << endl;  //Print original database
cout<<"Wszystko dziala"<<endl;
}

Cały kod .h:

#include <iostream>
#include <vector>

using namespace std;

 template <class Key, class T> class MapTemplate; 
 template <class Key, class T> ostream& operator<< (ostream &o,const MapTemplate<Key, T> &map);
template <class Key, class T> //template <klucze, dane pracownikow>
class MapTemplate{ 
private:
    vector<Key> keys;   //vector do przechowywania unikalnych kluczy pracowników
    vector<T> content;  //vector do przechowywania danych pracowników
public:

    MapTemplate(){}
    void Add(Key key, T t);
    T* Find(Key key);
friend ostream& operator<< <>(ostream &out,const MapTemplate<Key, T> &map);
MapTemplate (const MapTemplate &MapTemplateCopy) 
{
        content = MapTemplateCopy.content;
	keys = MapTemplateCopy.keys;

        cout << "Kopiowanie\n";
}
}; //koniec klasy MapTemplate

//Dodanie do bazy (Add)
template<class Key, class T>
void MapTemplate <Key, T>::Add(Key key, T t)
{
    keys.push_back(key);
    content.push_back(t);
}
//Szukanie w bazie (Find)
template<class Key, class T>
T* MapTemplate<Key, T>::Find(Key key)
{
    for(unsigned int i = 0; i < keys.size(); i++)
        if (keys[i] == key)
        {
            return &content.at(i);
        }
return nullptr;
}

//Początek klasy Employee bez template
class Employee
{
private:

public:
    Employee(string Name, string Position, int Age);
    string Name;
    int Age;
    string Position;

};//koniec klasy employee

//Dodanie pól Name, Age, Position
Employee::Employee(string Name, string Position, int Age)
{
    this->Name = Name;
    this->Age = Age;
    this->Position = Position;

}

//operator <<
template<class Key, class T>
ostream& operator<<(ostream &out,const MapTemplate<Key, T> &map)
{
	for(unsigned int i=0;i<map.content.size();i++)
	{
		out << map.keys[i] <<", " << map.content[i].Name << ", " <<map.content[i].Position << ", " <<map.content[i].Age <<endl;
	}
return out;
}

Wypis do konsoli:

761028073, Jan Kowalski, salesman, 28
510212881, Adam Nowak, storekeeper, 54
730505129, Anna Zaradna, secretary, 32

Kopiowanie   //Tu jak widać się wywołał konstuktor
761028073, Jan Kowalski, salesman, 29  //zaktualizowały się dane w oryginalnej bazie
510212881, Adam Nowak, salesman, 54
730505129, Anna Zaradna, secretary, 32

Wszystko dziala

Master, tak sprawdziłem jeszcze main'a do którego mam się dostosować i w nim jest lekka różnica niż w tym co podesłałem na początku na forum.
Zamiast

   Employee* pE;
    pE = Database.Find(510212881);       //Find employee using its ID
    pE->Position = "salesman";          //Modify the position of employee
    pE = Database.Find(761028073);     //Find employee using its ID
    pE->Age = 29;             //Modify the age of employee

jest:

   Employee* pE;
    pE = NewDatabase.Find(510212881);       //Find employee using its ID
    pE->Position = "salesman";          //Modify the position of employee
    pE = NewDatabase.Find(761028073);     //Find employee using its ID
    pE->Age = 29;             //Modify the age of employee

Tak więc nie wiem czy to coś zmienia ale zrobiłem sam konstruktor kopiujący i wszystko ładnie działa i sam konstruktor jest wywoływany, bo dałem cout'a w nim żeby sprawdzić. Czy ten operator= jest dalej potrzebny?

Ps: Nie zrobiłem konstruktora poza klasą, bo coś mi błędy wywalało, a szkoda mi czasu było xd W wolnej chwili to poprawię :)

1

Czy jest potrzebny - powiem tak:

    MapTemplate<ID,Employee> NewDatabase = Database; //tu się odpali konstruktor kopiujący
    ....
    ....
    Database = NewDatabase;//a tutaj operator przypisania

czyli jak widać jest w użyciu. ALE!
Jeśli wszystkie składniki klasy, w Twoim wypadku map_template mają zdefiniowany ten operator, oraz nie działasz na wskaźnikach w tej klasie to są spore szanse na to, że automatycznie generowany przez kompilator operator= wystarczy - wtedy nic nie trzeba dopisywać samemu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1