언어 자료구조 알고리즘/디딤돌 C++

[C++] 52. 함수 개체

언제나휴일 2016. 4. 25. 01:27
반응형


함수 개체

이번에는 함수 호출 연산자 중복 정의와 함수 개체를 알아보기로 해요.

 

C++언어에서는 함수 호출 연산자를 중복정의 할 수 있습니다. 함수 호출 연산자의 연산 기호는 ( ) 입니다. 따라서 함수 호출 연산자를 중복 정의할 때 메서드 이름은 operator()입니다. 메서드 뒤에 입력 매개 변수 리스트를 열거하는 ()에는 개발자가 개수와 형식을 결정하고 반환 형식도 개발자가 정합니다.

[반환형식] operator() ([입력 매개 변수 리스트]);

 

그리고 함수 호출 연산자를 중복 정의한 형식의 개체를 함수 개체라고 부릅니다. 함수 개체는 형식 내부에 함수 호출 연산자를 중복 정의하고 있어서 마치 함수처럼 호출하여 사용할 수 있습니다.

 

먼저 간단하게 함수 호출 연산자 중복 정의를 사용하여 함수 개체를 함수처럼 사용하는 예를 보여드를게요.


Program.cpp


//함수 호출 연산자 중복 정의

#include <iostream>

using namespace std;

class FunClass

{

public:

    int operator()(int a,int b)//함수 호출 연산자 중복 정의

    {

        cout<<"테스트"<<endl;

        return a*b;

    }

};

int main()

{

    FunClass fc;//함수 개체

 

    cout<<fc(3,4)<<endl;//함수 개체를 함수처럼 사용

    return 0;

}

 

▷ 실행 결과

테스트

12

보통 함수 개체는 메서드를 구현하는 곳에서 모든 알고리즘을 정의하지 못하고 일부를 호출하는 곳에서 정의한 알고리즘을 이용할 때 사용합니다. 예를 들어 회원을 보관하는 배열을 구현하면서 검색 기능을 구현할 때 호출하는 곳에서 검색 기능을 구현한 함수 개체를 입력 인자로 받아 이를 이용하는 것이죠. 또한 배열에 보관한 회원 정보를 출력하는 알고리즘을 호출하는 곳에서 함수 개체로 전달받아 이를 이용하여 출력하게 할 수도 있겠죠. 마찬가지로 배열에 보관한 회원 정보를 정렬할 때 비교 알고리즘을 함수 개체를 입력 인자로 전달받아 이용할 수도 있을 거예요.

 

다음처럼 배열에서는 함수 호출 연산자를 중복 정의한 알고리즘을 추상화합니다.

#define interface struct

interface IEqual

{

    virtual bool operator()(Member *member)=0;

};

 

그리고 배열의 검색 기능에서는 함수 개체를 입력 인자로 받아 조건에 맞는 것을 구현하죠.

Member *MemberCollection::FindIf(IEqual &ie)

{

    for(int i=0;i<usage;i++)

    {

        if(ie(base[i]))

        {

            return base[i];

        }

    }

    return 0;

}

 

사용하는 곳에서는 검색에 필요한 알고리즘을 구체적으로 구현합니다.

class EqualerNum:public IEqual

{

    int num;

public:

    EqualerNum(int num)

    {

        this->num = num;

    }

    virtual bool operator()(Member *member)

    {

        return num == member->GetNum();

    }

};

 

 

그리고 배열의 검색 요청 시에 구체적으로 구현한 함수 개체를 입력 인자로 전달하여 원하는 것을 찾습니다.

MemberCollection mc(10);

...중략...

EqualerNum en(3);

Member *member = mc.FindIf(en);

if(member==0)

{

    cout<<"검색 실패"<<endl;

}

else

{

    cout<<"번호:"<<member->GetNum()<<" 이름:"<<member->GetName()<<endl;

}

다음은 함수 개체를 이용하여 회원 컬렉션을 정의하고 이를 이용하는 예제 코드입니다.


함수 개체를 이용한 회원 배열 구현.zip


//Member.h

#pragma once

#include <iostream>

#include <string>

using namespace std;

class Member

{

    const int num;

    string name;

public:

    Member(int num,string name);

    int GetNum()const; //회원 번호 접근자

    string GetName()const; //회원 이름 접근자

};

 

//Member.cpp

#include "Member.h"

Member::Member(int num,string name):num(num)

{

    this->name = name;

}

int Member::GetNum()const

{

    return num;

}

string Member::GetName()const

{

    return name;

}

//MemberCollection.h

#pragma once

#include "Member.h"

 

#define interface struct

 

interface IEqual//조건 알고리즘 추상화

{

    virtual bool operator()(Member *member)=0;

};

interface IDoSome //회원에 관한 알고리즘 추상화

{

    virtual void operator() (Member *member)=0;

};

interface ICompare//회원 비교 알고리즘 추상화

{

    virtual int operator()(Member *m1,Member *m2)=0;

};

class MemberCollection

{

    Member **base;

    const int max_member;

    int usage;

public:

    MemberCollection(int max);

    ~MemberCollection(void);

    void PushBack(Member *member);//순차 보관

    Member *FindIf(IEqual &ie); //조건에 맞는 개체 탐색

    void ListMember(IDoSome &iv); //전체 회원 데이터에 알고리즘 적용

    void Sort(ICompare &ic); //검색 알고리즘 이용하여 정렬

};

 

//MemberCollection.cpp

#include "MemberCollection.h"

MemberCollection::MemberCollection(int max):max_member(max)

{

    base = 0;

    if(max)

    {

        base = new Member *[max];

    }

    usage = 0;

}

MemberCollection::~MemberCollection(void)

{

    if(base)

    {

        delete[] base;

    }

}

 

void MemberCollection::PushBack(Member *member)

{

    if(usage<max_member)

    {

        base[usage] = member;

        usage++;

    }

}

 

Member *MemberCollection::FindIf(IEqual &ie)

{   

    for(int i=0;i<usage;i++)

    {

        if(ie(base[i])) //조건 알고리즘을 사용

        {

            return base[i];

        }

    }

    return 0;

}

 

void MemberCollection::ListMember(IDoSome &iv)

{

    for(int i=0;i<usage;i++)

    {

        iv(base[i]);//회원에 관한 알고리즘 사용

    }

}

 

void MemberCollection::Sort(ICompare &ic)

{

    for(int i=usage;i>1;i--)

    {

        for(int j=1;j<i;j++)

        {

            if(ic(base[j-1],base[j])>0) //비교 알고리즘 사용

            {

                Member *temp = base[j-1];

                base[j-1] = base[j];

                base[j]=temp;

            }

        }

    }

}

 

//Program.cpp

#include "MemberCollection.h"

 

class EqualerNum:public IEqual //번호로 비교 알고리즘

{

    int num;

public:

    EqualerNum(int num)

    {

        this->num = num;

    }

    virtual bool operator()(Member *member)

    {

        return num == member->GetNum();

    }

};

 

class ViewMember:public IDoSome//회원 출력 알고리즘

{

public:

    virtual void operator() (Member *member)

    {

        cout<<"번호:"<<member->GetNum()<<" 이름:"<<member->GetName()<<endl;

    }

};

 

 

class ViewMember2:public IDoSome//회원 출력 알고리즘2

{

public:

    virtual void operator() (Member *member)

    {

        cout<<"이름:"<<member->GetName()<<" 번호:"<<member->GetNum()<<endl;

    }

};

 

class Dispose:public IDoSome////회원에 관한 소멸 알고리즘

{

    public:

    virtual void operator() (Member *member)

    {

        delete member;

    }

};

 

class CompareByNum:public ICompare//번호로 비교 알고리즘

{

public:

    virtual int operator()(Member *m1,Member *m2)

    {

        return m1->GetNum()-m2->GetNum();

    }

};

 

class CompareByName:public ICompare//이름으로 비교 알고리즘

{

public:

    virtual int operator()(Member *m1,Member *m2)

    {

        string s1 = m1->GetName();

        string s2 = m2->GetName();

        return s1.compare(s2);

    }

};

 

int main()

{

    MemberCollection mc(10);

 

    mc.PushBack(new Member(5,"이순신"));

    mc.PushBack(new Member(3,"홍길동"));

    mc.PushBack(new Member(1,"강감찬"));   

 

    EqualerNum en(3);//번호로 검색 알고리즘 함수 개체

    Member *member = mc.FindIf(en);//입력 인자로 함수 개체 전달

    if(member==0)

    {

        cout<<"검색 실패"<<endl;

    }

    else

    {

        cout<<"번호:"<<member->GetNum()<<" 이름:"<<member->GetName()<<endl;

    }

   

    cout<<"전체 출력1"<<endl;

    ViewMember vm;//회원 출력 알고리즘 함수 개체

    mc.ListMember(vm);//입력 인자로 함수 개체 전달

 

    cout<<"전체 출력2"<<endl;

    ViewMember2 vm2;//회원 출력 알고리즘2 함수 개체

    mc.ListMember(vm2);//입력 인자로 함수 개체 전달

 

    cout<<"번호로 정렬 후 출력"<<endl;

    CompareByNum cbnum;//번호로 비교 알고리즘 함수 개체

    mc.Sort(cbnum);//입력 인자로 함수 개체 전달

    mc.ListMember(vm);//입력 인자로 함수 개체 전달

 

    cout<<"이름으로 정렬 후 출력"<<endl;

    CompareByName cbname;//이름으로 비교 알고리즘 함수 개체

    mc.Sort(cbname);//입력 인자로 함수 개체 전달

    mc.ListMember(vm2);//입력 인자로 함수 개체 전달

 

 

    Dispose dispose;//소멸 알고리즘 함수 개체

    mc.ListMember(dispose);//입력 인자로 함수 개체 전달

 

    return 0;

}

실행 결과

번호:3 이름:홍길동

전체 출력1

번호:5 이름:이순신

번호:3 이름:홍길동

번호:1 이름:강감찬

전체 출력2

이름:이순신 번호:5

이름:홍길동 번호:3

이름:강감찬 번호:1

번호로 정렬 후 출력

번호:1 이름:강감찬

번호:3 이름:홍길동

번호:5 이름:이순신

이름으로 정렬 후 출력

이름:강감찬 번호:1

이름:이순신 번호:5

이름:홍길동 번호:3

반응형