1

Тема: Чи можна написати універсальну функцію замість декількох схожих

Добрий день! Я прикріпив частину коду який виконує пошук по записах. Ця функція шукає якесь певне значення PlayerIndex. Така ж сама функція може шукати PlayerAge, якщо тут

int f = atoi( player[i].PlayerIndex.c_str());

PlayerIndex замінити на PlayerAge. Чи можна написати якусь універсальну функцію, щоб можна було вказати по яких саме значеннях проводити пошук, замість того щоб писати окрему функцію пошуку для кожного значення?

void FUNCTION::Search_Int(int A)
{
    
    int search = A;
    int i = 0, max;
    PLAYER player[SIZE1]; 
    ifstream file("basket.txt");
    if (!file)
    {
        return;
    }
    
    else
    {
        while (!file.eof())
        {
            file >> player[i].PlayerIndex >>  player[i].PlayerName>>  player[i].PlayerName1>>  player[i].PlayerNationality >>  player[i].PlayerClub >>  player[i].PlayerAge;
            file >>  player[i].PlayerPosition >>  player[i].PlayerWeight >>  player[i].PlayerHeight >>  player[i].PlayerMatches >>  player[i].PlayerPrice >>  player[i].PlayerPoints;
            i++;
        }

        
        max = i;
        cout << lin_e << endl;
        for (i = 0; i<max; i++)
        {
            int f = atoi( player[i].PlayerIndex.c_str()); // перетворення string y int

            if (f == search)
            {
                cout <<  player[i].PlayerIndex << '\t' << '|' << '\t' <<  player[i].PlayerName<< " " <<  player[i].PlayerName1 << '\t' << '|' << '\t' <<  player[i].PlayerNationality << '\t' << '|' << '\t';
                cout <<  player[i].PlayerClub << '\t' << '|' << '\t' <<  player[i].PlayerAge << '\t' << '|' << '\t' <<  player[i].PlayerPosition << '\t' << '|' << '\t' <<  player[i].PlayerWeight << '\t' << '|' << '\t';
                cout <<  player[i].PlayerHeight << '\t' << '|' << '\t' <<  player[i].PlayerMatches<< '\t' << '|' << '\t' <<  player[i].PlayerPrice << '\t' << '|' << '\t';
                cout <<  player[i].PlayerPoints << '\t' << '|' << '\t' << endl;
                cout << line << endl;
            }

        }
    }
    file.close();
    return;
}

2

Re: Чи можна написати універсальну функцію замість декількох схожих

Щось можна придумати, наприклад, можна написати метод в структурі, який через switch буде видавати значення. Але всеодно імена змінних доведеться писати ручками. Так що по суті це одне і теж, в будь-якому випадку доведеться все писати.

Подякували: Vasia Hudyma1

3 Востаннє редагувалося koala (27.04.2017 06:03:42)

Re: Чи можна написати універсальну функцію замість декількох схожих

Ви не подали визначення вашого PLAYER, тому можливі помилки в тому, що я пишу.
Дуже раджу:
- виправити назви класів/структур і елементів. Виключно з великих літер прийнято давати назви макросам. Порівняйте

PLAYER player;
player.PlayerIndex = 10;

та

Player player;
player.index = 10;

- додати функції введення та виведення; якщо ще не розбирали перевизначення операторів (а тут istream::operator>> дуже проситься), то зробіть хоча б Player::input(istream *) і Player::output(ostream *).
- тут не потрібен масив, все можна робити в одному циклі;
- замість

if(помилка){
    return;
} else {
    основна гілка
}

робіть або

if(все добре) {
    основна гілка
} //else не потрібен

або

if(помилка) {
    return;
}
основна гілка

Ну і останній return зайвий - якщо, звісно, його не вимагає гайдлайн.

Тепер до вашого питання - тут є три способи: макрос, посилання на елемент та посилання на функцію. Ось всі приклади: http://ideone.com/QF1cN8

Прихований текст
#include <iostream>

using namespace std;

struct Pair{
    int a;
    int b;
};

ostream& operator<<(ostream& os, const Pair& p) {
    return os<<"("<<p.a<<", "<<p.b<<")";
}

void find_ptr_member(Pair array[], int size, int Pair::*where, int what){
    for(int i=0;i<size;++i){
        if(array[i].*where==what){
            cout<<"Found with pointer to member "<<array[i]<<endl;
        }
    }
}

void find_ptr_func(Pair array[], int size, bool (*isIt)(Pair&)){
    for(int i=0;i<size;++i){
        if(isIt(array[i])){
            cout<<"Found with pointer to function "<<array[i]<<endl;
        }
    }
}

#define FIND_MACRO(array, size, member, value) {       \
    for(int i=0;i<size;++i){                           \
        if(array[i].member==value){                    \
            cout<<"Found with macro "<<array[i]<<endl; \
        }                                              \
    }                                                  \
}

int main() {
    Pair p[10];
    for(int i=0;i<10;++i){
        p[i].a=i;
        p[i].b=10-i;
    }
    find_ptr_member(p,10,&Pair::b,3);
    find_ptr_func(p,10,[](Pair&p){return p.b==6;});
    FIND_MACRO(p,10,b,2);
    return 0;
}

Звісно, якщо треба шукати елементи різних типів за допомогою посилання на елемент, треба скористатися узагальненим програмуванням, тобто шаблонами.
І ще з умови не зрозуміло, чи треба шукати всі записи, що нас влаштовують, чи тільки перший, у другому випадку цикл треба обривати.

Подякували: 0x9111A, Vasia Hudyma, ReAl, sensei4

4 Востаннє редагувалося Vasia Hudyma (27.04.2017 18:54:29)

Re: Чи можна написати універсальну функцію замість декількох схожих

koala написав:

Ви не подали визначення вашого PLAYER, тому можливі помилки в тому, що я пишу.
Дуже раджу:
- виправити назви класів/структур і елементів. Виключно з великих літер прийнято давати назви макросам. Порівняйте

PLAYER player;
player.PlayerIndex = 10;

та

Player player;
player.index = 10;

- додати функції введення та виведення; якщо ще не розбирали перевизначення операторів (а тут istream::operator>> дуже проситься), то зробіть хоча б Player::input(istream *) і Player::output(ostream *).
- тут не потрібен масив, все можна робити в одному циклі;
- замість

if(помилка){
    return;
} else {
    основна гілка
}

робіть або

if(все добре) {
    основна гілка
} //else не потрібен

або

if(помилка) {
    return;
}
основна гілка

Ну і останній return зайвий - якщо, звісно, його не вимагає гайдлайн.

Тепер до вашого питання - тут є три способи: макрос, посилання на елемент та посилання на функцію. Ось всі приклади: http://ideone.com/QF1cN8

Прихований текст
#include <iostream>

using namespace std;

struct Pair{
    int a;
    int b;
};

ostream& operator<<(ostream& os, const Pair& p) {
    return os<<"("<<p.a<<", "<<p.b<<")";
}

void find_ptr_member(Pair array[], int size, int Pair::*where, int what){
    for(int i=0;i<size;++i){
        if(array[i].*where==what){
            cout<<"Found with pointer to member "<<array[i]<<endl;
        }
    }
}

void find_ptr_func(Pair array[], int size, bool (*isIt)(Pair&)){
    for(int i=0;i<size;++i){
        if(isIt(array[i])){
            cout<<"Found with pointer to function "<<array[i]<<endl;
        }
    }
}

#define FIND_MACRO(array, size, member, value) {       \
    for(int i=0;i<size;++i){                           \
        if(array[i].member==value){                    \
            cout<<"Found with macro "<<array[i]<<endl; \
        }                                              \
    }                                                  \
}

int main() {
    Pair p[10];
    for(int i=0;i<10;++i){
        p[i].a=i;
        p[i].b=10-i;
    }
    find_ptr_member(p,10,&Pair::b,3);
    find_ptr_func(p,10,[](Pair&p){return p.b==6;});
    FIND_MACRO(p,10,b,2);
    return 0;
}

Звісно, якщо треба шукати елементи різних типів за допомогою посилання на елемент, треба скористатися узагальненим програмуванням, тобто шаблонами.
І ще з умови не зрозуміло, чи треба шукати всі записи, що нас влаштовують, чи тільки перший, у другому випадку цикл треба обривати.

Дуже вам вдячний! Мені підійшло посилання на елемент. І дякую за поради)
P.S. PLAYER це клас.

5

Re: Чи можна написати універсальну функцію замість декількох схожих

Vasia Hudyma написав:

PLAYER це клас.

А Player - було б взагалі супер :)

Подякували: ostap34PHP1

6

Re: Чи можна написати універсальну функцію замість декількох схожих

koala написав:
Vasia Hudyma написав:

PLAYER це клас.

А Player - було б взагалі супер :)

А я потім і змінив на Player :)

7

Re: Чи можна написати універсальну функцію замість декількох схожих

То, може, поділитеся остаточним варіантом коду?
І ще питання: ви пишете під C++03 чи пізніші версії?

8

Re: Чи можна написати універсальну функцію замість декількох схожих

class Player
{
private:
    string index;
    string name;
    string name1;
    string nationality;
    string position;
    string age;
    string weight;
    string height;
    string matches;
protected:
    string price;
    string player_club;
    string player_points;
public:
    void Set_Data();

    friend class FUNCTION;
    void Search_Int(Player player[], string Player::*where, int A);
};

class FUNCTION
{
public:
    void Search_Data();


private:

};

    void Search_Data()
    {

    }
    
    void Player::Set_Data()
    {
        Player pl[10];

    
    int X;
    cout << "Enter int: "; cin >> X;
    Player::Search_Int(pl,&Player::index,X);    

    return;
    }

void Player::Search_Int(Player player[], string Player::*where, int A)
{
    
    int search = A;
    int  i = 0, max;
    
    ifstream file("basket.txt");
    if (!file)
    {
        return;
    }
    else

        while (!file.eof())
        {
            file >> player[i].index >>  player[i].name>>  player[i].name1>>  player[i].nationality >>  player[i].player_club >>  player[i].age;
            file >>  player[i].position >>  player[i].weight >>  player[i].height >>  player[i].matches >>  player[i].price >>  player[i].player_points;
            i++;
        }


        
        max = i;
        
        for (i = 0; i<max; i++)
        {
        
    
int f = atoi( (player[i].*where).c_str());
            if ( A == f )
            {
                cout <<  player[i].index << '\t' << '|' << '\t' <<  player[i].name<< " " <<  player[i].name1 << '\t' << '|' << '\t' <<  player[i].nationality << '\t' << '|' << '\t';
                cout <<  player[i].player_club << '\t' << '|' << '\t' <<  player[i].age << '\t' << '|' << '\t' <<  player[i].position << '\t' << '|' << '\t' <<  player[i].weight << '\t' << '|' << '\t';
                cout <<  player[i].height << '\t' << '|' << '\t' <<  player[i].matches<< '\t' << '|' << '\t' <<  player[i].price << '\t' << '|' << '\t';
                cout <<  player[i].player_points << '\t' << '|' << '\t' << endl;
                
            }

        }
    
    file.close();
    return;
}

main()
{
    


    Player obj;
    

    obj.Set_Data();    

    return 0;

}

- кінцевий варіант коду. Але це так би мовити "чорновик".

9

Re: Чи можна написати універсальну функцію замість декількох схожих

koala написав:

То, може, поділитеся остаточним варіантом коду?
І ще питання: ви пишете під C++03 чи пізніші версії?

Я тільки навчаюсь, тому не можу сказати на якій версії пишу.