[ 12주차 - 2 ]
일반 함수
일반 함수 : 여러 가지 자료형에 적용될 일반적인 연산들
일반 함수를 생성함으로써 데이터의 종류와는 독립적으로 알고리즘의 특성을 정의할 수 있다.
일반 함수가 정의되면 컴파일러는 함수가 실행될 때 사용되는 자료형을 위한 정확한 코드를 자동으로 만들어낸다.
일반 함수 키워드는 template를 사용함으로써 생성된다.
template < class Ttype > ret-type func-name( parameter-list ) {
...
}
type : 함수에 의해 사용될 자료형을 나타내는 이름
#include <iostream>
using namespace std;
template <class X> void swapargs(X& a, X& b) {
X temp;
temp = a;
a = b;
b = temp;
}
X는 자리만 잡아주는 일반 자료형이고, 컴파일러가 특정한 버전의 함수를 생성할 때 실제 자료형으로 대체된다.
X에는 int, float, double 등이 올 수 있으며 실행시에 결정이 된다.
하나의 일반 자료형을 갖는 함수
#include <iostream>
using namespace std;
template <class X> void swapargs(X& a, X& b) {
X temp;
temp = a;
a = b;
b = temp;
}
int main() {
int i = 20, j = 20;
double x = 10.1, y = 23.3;
char a = 'x', b = 'z';
cout << "Original i, j : " << i << " " << j << "\n";
cout << "Original x, y : " << x << " " << y << "\n";
cout << "Original a, b : " << a << " " << b << "\n";
swapargs(i, j); // 정수 교환
swapargs(x, y); // 실수 교환
swapargs(a, b); // 문자 교환
cout << "Swapped i, j : " << i << " " << j << "\n";
cout << "Swapped x, y : " << x << " " << y << "\n";
cout << "Swapped a, b : " << a << " " << b << "\n";
return 0;
}
//Original i, j : 20 20
//Original x, y : 10.1 23.3
//Original a, b : x z
//Swapped i, j : 20 20
//Swapped x, y : 23.3 10.1
//Swapped a, b : z x
두 개의 일반 자료형을 갖는 함수
#include <iostream>
using namespace std;
template <class type1, class type2> void myfunc(type1 x, type2 y) {
cout << x < " " << y << "\n";
}
int main() {
myfunc(10, "hi");
myfunc(0.23, 10L);
return 0;
}
//10 hi
//0.23 10
template 문에서 콤마로 분리되는 리스트를 사용함으로써 두 개 이상의 일반 자료형을 정의할 수 있다.
일반 함수 중복하기
#include <iostream>
using namespace std;
template <class X> void swapargs(X& a, X& b) {
X temp;
temp = a;
a = b;
b = temp;
cout << "Inside template swapargs\n";
}
// int 형을 위해 swapargs의 일반 함수 버전을 중복한다.
// 중복된 함수는 특정한 버전과 관련하여 일반 함수를 중복한다.
void swapargs(int& a, int& b) {
int temp;
temp = a;
a = b;
b = temp;
cout << "Inside swapargs int specialization\n";
}
매개 변수가 둘 다 int일 경우의 중복된 함수가 구체적으로 명시되어 있다면 매개변수가 int일 경우의 함수가 먼저 호출이 되고 다른 매개 변수 형들은 template 함수가 호출이 된다.
#include <iostream>
using namespace std;
template <class X> void swapargs(X& a, X& b) {
X temp;
temp = a;
a = b;
b = temp;
cout << "Inside template swapargs\n";
}
// int 형을 위해 swapargs의 일반 함수 버전을 중복한다.
// 중복된 함수는 특정한 버전과 관련하여 일반 함수를 중복한다.
void swapargs(int& a, int& b) {
int temp;
temp = a;
a = b;
b = temp;
cout << "Inside swapargs int specialization\n";
}
int main() {
int i = 20, j = 20;
double x = 10.1, y = 23.3;
char a = 'x', b = 'z';
cout << "Original i, j : " << i << " " << j << "\n";
cout << "Original x, y : " << x << " " << y << "\n";
cout << "Original a, b : " << a << " " << b << "\n";
swapargs(i, j); // 명시적으로 중복된 swapargs()를 호출
swapargs(x, y); // 일반 함수 swapargs()를 호출
swapargs(a, b); // 일반 함수 swapargs()를 호출
cout << "Swapped i, j : " << i << " " << j << "\n";
cout << "Swapped x, y : " << x << " " << y << "\n";
cout << "Swapped a, b : " << a << " " << b << "\n";
return 0;
}
//Original i, j : 20 20
//Original x, y : 10.1 23.3
//Original a, b : x z
//Inside swapargs int specialization
//Inside template swapargs
//Inside template swapargs
//Swapped i, j : 20 20
//Swapped x, y : 23.3 10.1
//Swapped a, b : z x
매개 변수가 정수형일 경우 일반 함수가 명시적으로 중복되었기 때문에 컴파일러는 일반 버전의 swapargs() 함수를 생성하지 않는다.
함수 template 중복하기
#include <iostream>
using namespace std;
// f() 템플리트의 첫번째 버전
template <class X> void f(X a) {
cout << "Inside f(X a)\n";
}
// f() 템플리트의 두번째 버전
template <class X, class Y> void f(X a, Y b) {
cout << "Inside f(X a, Y b)\n";
}
int main() {
f(10); //f(X)를 호출한다.
f(10, 20); // f(X,Y)를 호출한다.
return 0;
}
//Inside f(X a)
//Inside f(X a, Y b)
template 명세를 중복할 수 있다. 그렇게 하기 위해서 매개변수 리스트에서 다른 것과 구별이 되는 템플리트 버전을 생성한다.
템플리트 함수와 함께 표준 매개변수를 사용하기
#include <iostream>
using namespace std;
template <class X> void repeat(X data, int times) {
do {
cout << data << "\n";
times--;
} while (times);
}
int main() {
repeat("This is a test", 3);
repeat(100, 5);
repeat(99.0 / 2, 4);
return 0;
}
//This is a test
//This is a test
//This is a test
//100
//100
//100
//100
//100
//49.5
//49.5
//49.5
//49.5
첫번째 매개변수는 템플릿 자료형을 사용하고 두번째 매개변수는 일반 자료형이다. 즉, 표준 매개변수와 일반 자료형 매개변수를 템플리트 함수에서 섞어 쓸 수 있다.
매개변수가 반드시 템플리트 자료형이 되어야 하는 것은 아니다.
일반 클래스
일반 클래스를 정의할 때 그 클래스에 의해 사용되는 모든 알고리즘을 정의하는 클래스를 생성한다. 그러나 조작되는 데이터의 실제 자료형은 그 클래스의 객체가 생성될 때 매개변수로 명시된다.
일반 클래스는 클래스가 일반화될 수 있는 연산을 사용할 때 유용하다.
template <class Ttype> class class-name{
...
}
Ttype : 자리만 차지하는 형 이름 ( 클래스가 인스턴스화될 때 명시됨 )
Ttype에 객체를 생성할 때 대응하는 자료형을 반드시 명시해야한다. 명시를 안해주면 컴파일 에러가 난다.
* 일반 클래스의 인스턴스 생성 형식
class-name <type> ob ( type : 클래스가 동작할 데이터의 형 이름 )
일반 클래스의 멤버 함수들은 자동으로 일반 함수가 되므로 template를 사용할 필요는 없다.
일반 클래스 예
#include <iostream>
using namespace std;
const int SIZE = 100;
template < class QType > class queue {
private:
QType q[SIZE];
int sloc, rloc;
public:
queue() {
sloc = rloc = 0;
}
void qput(QType i);
QType qget();
};
QType에는 어떠한 자료형도 사용될 수 있다. 멤버함수들은 다 똑같고 클래스만 QType 자료형이다.
queue에서 삽입, 삭제에 해당하는 자료형은 역시 QType이 되어야한다.
// 하나의 원소를 큐에 넣는다.
template <class QType> void queue<QType>::qput(QType i) {
if (sloc == SIZE) {
cout << "Queue is full.\n";
return;
}
sloc++;
q[sloc] = i;
}
// 큐에서 하나의 원소를 얻는다.
template <class QType> QType queue<QType>::qget() {
if (rloc == sloc) {
cout << "Queue Underflow.\n";
return 0;
}
rloc++;
return q[rloc];
}
템플리트 클래스 내에 존재하는 멤버 함수들은 템플리트 클래스를 명시해주는 문법을 지켜야한다.
#include <iostream>
using namespace std;
const int SIZE = 100;
template < class QType > class queue {
private:
QType q[SIZE];
int sloc, rloc;
public:
queue() {
sloc = rloc = 0;
}
void qput(QType i);
QType qget();
};
// 하나의 원소를 큐에 넣는다.
template <class QType> void queue<QType>::qput(QType i) {
if (sloc == SIZE) {
cout << "Queue is full.\n";
return;
}
sloc++;
q[sloc] = i;
}
// 큐에서 하나의 원소를 얻는다.
template <class QType> QType queue<QType>::qget() {
if (rloc == sloc) {
cout << "Queue Underflow.\n";
return 0;
}
rloc++;
return q[rloc];
}
int main() {
queue<int> a, b; // 2개의 정수 큐를 생성한다.
a.qput(10);
b.qput(10);
a.qput(20);
b.qput(1);
cout << a.qget() << " ";
cout << a.qget() << " ";
cout << b.qget() << " ";
cout << b.qget() << "\n";
queue<double> c, d; // 2개의 실수 큐를 생성한다.
c.qput(10.12);
d.qput(19.99);
c.qput(-20.0);
d.qput(0.986);
cout << c.qget() << " ";
cout << c.qget() << " ";
cout << d.qget() << " ";
cout << d.qget() << "\n";
return 0;
}
//10 20 10 1
//10.12 -20 19.99 0.986
QType형에는 int queue class나 double queue class를 사용할 수 있다.
두 개의 일반 자료형을 가진 예
#include <iostream>
using namespace std;
template <class Type1, class Type2> class myclass {
Type1 i;
Type2 j;
public:
myclass(Type1 a, Type2 b) {
i = a;
j = b;
}
void show() {
cout << i << " " << j << "\n";
}
};
int main() {
myclass<int, double> ob1(10, 0.23);
myclass<char, char*> ob2('X', "This is a test");
ob1.show(); // int와 double을 보여준다.
ob2.show(); // char와 char*를 보여준다.
return 0;
}
실습문제
n값을 받아 n크기의 배열을 동적으로 생성하고 n개의 값을 입력받아 그 배열에 저장하고, 최대값을 출력하는 일반 클래스를( template class)를 작성하라
멤버변수 : size, arr[]
멤버함수 : 생성자함수, input(), max()
테스트 : main 함수에서 5개의 정수와 3개의 실수에 대해 테스트하기
'2CHAECHAE 학교생활 > 객체지향프로그래밍(C++)' 카테고리의 다른 글
[ 객체지향프로그래밍(C++) 13주차 ① ] (0) | 2022.06.04 |
---|---|
[ 객체지향프로그래밍(C++) 12주차 ① ] (0) | 2022.05.22 |
[ 객체지향프로그래밍(C++) 11주차 ① ] (0) | 2022.05.16 |
[ 객체지향프로그래밍(C++) 10주차 ② ] (0) | 2022.05.16 |
[ 객체지향프로그래밍(C++) 10주차 ① ] (0) | 2022.05.09 |