19. Class-Templates & Typedef
19 Sep 2019 | C++
Templates
- 템플릿(template)이란 매개변수의 타입에 따라 함수나 클래스를 생성하는 메커니즘을 의미합니다.
- 템플릿은 타입이 매개변수에 의해 표현되므로, 매개변수화 타입(parameterized type)이라고도 불립니다
- 템플릿을 사용하면 타입마다 별도의 함수나 클래스를 만들지 않고, 여러 타입에서 동작할 수 있는 단 하나의 함수나 클래스를 작성하는 것이 가능합니다.
2. Function Template(함수 템플릿)
- C++에서 함수 템플릿(function template)이란 함수의 일반화된 선언을 의미합니다
- 함수 템플릿을 사용하면 같은 알고리즘을 기반으로 하면서, 서로 다른 타입에서 동작하는 함수를 한 번에 정의할 수 있습니다.
- 임의의 타입으로 작성된 함수에 특정 타입을 매개변수로 전달하면, C++ 컴파일러는 해당 타입에 맞는 함수를 생성해 줍니다
문법
```
template
함수의 원형
{
// 함수의 본체
}
- 위에서 정의된 타입 이름은 함수의 원형과 본체에서 임의의 타입으로 사용할 수 있습니다
- **이렇게 정의된 함수 템플릿을 호출할 때 매개변수로 int형을 전달하면, 함수의 원형과 본체에서 정의된 타입 이름은 모두 int형으로 바뀌게 됩니다.**
> 예제
template
void Swap(T& a, T& b);
int main(void)
{
int c = 2, d = 3;
cout << "c : " << c << ", d : " << d << endl;
Swap(c, d);
cout << "c : " << c << ", d : " << d << endl;
string e = "hong", f = "kim";
cout << "e : " << e << ", f : " << f << endl;
Swap(e, f);
cout << "e : " << e << ", f : " << f << endl;
return 0;
}
template
void Swap(T& a, T& b)
{
T temp;
temp = a;
a = b;
b = temp;
}
> 실행 결과
c : 2, d : 3
c : 3, d : 2
e : hong, f : kim
e : kim, f : hong
- 함수 템플릿이 각각의 타입에 대해 처음으로 호출될 때, C++ 컴파일러는 해당 타입의 인스턴스를 생성합니다.
- 이렇게 생성된 인스턴스는 해당 타입에 대해 특수화된 템플릿 함수입니다.
- 이 인스턴스는 함수 템플릿에 해당 타입이 사용될 때마다 호출됩니다.
## 3. 명시적 특수화(explicit specialization)
- C++의 함수 템플릿은 특정 타입에 대한 명시적 특수화를 제공하여, 해당 타입에 대해 특별한 동작을 정의할 수 있게 해줍니다.
- 컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 템플릿을 찾지 않고 해당 정의를 사용합니다.
- 앞서 정의된 함수 템플릿 Swap의 double형에 대한 명시적 특수화는 다음과 같습니다.
> 함수 템플릿 원형
template
void Swap(T& a, T& b);
template void Swap(T& a, T& b);
> double형을 위한 명시적 특수화
template <> void Swap(double&, double&) { ... };
# [Typedef](https://wikidocs.net/419)
- typedef는 새로운 타입을 만드는 것이 아니라 타입의 새로운 별칭을 정의하는 키워드 입니다
typedef int TypedefInt;
TypedefInt a;
- 이 키워드가 템플릿과 무슨 관계인지 설명하겠습니다
- typedef는 클래스 안에서 타입의 새로운 별칭을 지을 수 있습니다
class MyTypeClass
{
public:
typedef int Type1;
};
int main()
{
MyTypeClass a;
MyTypeClass::Type1 b;
return 0;
}
- a는 MyTypeClass의 객체, b는 int 변수
class MyTypeClass
{
public:
typedef int Type1;
private:
typedef double Type2;
};
int main()
{
MyTypeClass a;
MyTypeClass::Type1 b;
MyTypeClass::Type2 c; //에러
return 0;
}
class MyTypeClass
{
public:
typedef int Type1;
void f()
{
Type2 c;
}
private:
typedef double Type2;
};
int main()
{
MyTypeClass a;
MyTypeClass::Type1 b;
return 0;
}
- typedef은 클래스 안에서도 타입의 별칭을 만들 수 있을 뿐 아니라 외부접근 제한 까지 영향을 받습니다.
- typedef는 템플릿 파라미터로 받은 데이터 타입이 필요할 때가 있습니다
#include
template
class MyTempClass
{
public:
typedef T TempType;
};
int main()
{
MyTempClass a;
MyTempClass::TempType b;
MyTempClass c;
MyTempClass::TempType d;
return 0;
}
- 이렇게 타입안에 타입의 객체를 호출 할 수 있습니다. **이렇게 템플릿 매개변수에 종속된 것을 의존 이름(dependent name)** 이라고 합니다
- 클래스안에 중첩된 경우가 있는데 **중첩 의존 이름(nested dependent name)** 이라고 합니다.
- 확히 하면 클래스 안에 TempType 이라는 타입이 있으니까 **중첩 의존 타입 이름(nested dependent type name)** 이라고 합니다.
# Exercise 1
> main.cpp
#include
#include "point.h"
using namespace std;
/* function templates generalization*/
void operationOnPoints();
template<typename T, typename T2>
T add(T var1, T2 var2)
{
return var1 + var2;
}
/*
template<>
Point2D add(Point2D var1, Point2D var2)
{
Point2D tmp;
tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());
return tmp; } */ typedef Point<int> PointInt; int main() {
operationOnPoints();
//cout << add<double, double>(2, 5.6) << endl;
// cout « static_cast(6.5) << endl;
return 0; } void operationOnPoints() { // PointInt a(5);
Point<int*> b(49);
//cout << a.getX() << endl;
//cout << b.getX() << endl; }
> point.h
#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED
#include
using namespace std;
template
class Point //base, parent, superclass
{
protected:
T x;
public:
Point(T =0);
~Point();
T getX();
void setX(T);
};
template
Point::Point(T x)
{
this->x = x;
cout << "The constructor from the Point class has just been invoked" << endl;
}
template
Point::~Point()
{
cout << "The destructor from the Point class has just been invoked" << endl;
}
template
void Point::setX(T x)
{
this->x = x;
cout << "Im from Point" << endl;
}
template
T Point::getX()
{
return this->x;
}
template<>
double Point::getX()
{
cout <<"this function will be executed only when Point" << endl;
return this->x;
}
template
class Point<K*>
{
public:
Point(K a=0) { cout << "you can't use pointers here"; }
};
template
class Point2D : public Point //derived, child, subclass
{
protected:
T y;
public:
Point2D(T =0, T =0);
~Point2D();
T getY() { return y; }
void setY(T);
void setX(T);
void setXY(T, T);
Point2D operator+(Point2D);
};
template
Point2D::Point2D(T x, T y) : Point(x)
{
this->y = y;
cout << "The constructor from the Point2D class has just been invoked" << endl;
}
template
Point2D::~Point2D()
{
cout << "The destructor from the Point2D class has just been invoked" << endl;
}
template
void Point2D::setY(T y)
{
this->y = y;
}
template
void Point2D::setXY(T x, T y)
{
setX(x);
setY(y);
}
template
void Point2D::setX(T x)
{
this->x = x;
cout << "Im from Point2D" << endl;
}
template
Point2D Point2D::operator+(Point2D o)
{
Point2D tmp;
tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());
return tmp; } /* class Point3D : public Point2D {
};
*/
template<>
class Point
{
public:
Point(char a=0) { cout << "this is from Point";}
};
/*
class Point2D : public Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - public
class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected
class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private
*/
#endif // POINT_H_INCLUDED
# Exercise 2
> main.cpp
#include
#include "point.h"
using namespace std;
/* function templates generalization*/
void operationOnPoints();
template<typename T, typename T2>
T add(T var1, T2 var2)
{
return var1 + var2;
}
/*
template<>
Point2D add(Point2D var1, Point2D var2)
{
Point2D tmp;
tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());
return tmp; } */ int main() {
operationOnPoints();
//cout << add<double, double>(2, 5.6) << endl;
// cout « static_cast(6.5) << endl;
return 0; } void operationOnPoints() {
Point2D p1(10, 67);
Point2D p2(50, 3); // 60,70
Point2D sum = add(p1,p2);
cout << sum.getX() << endl;
cout << sum.getY() << endl;
}
> point.h
#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED
class Point //base, parent, superclass
{
protected:
int x;
public:
Point(int =0);
~Point();
int getX() { return x; }
void setX(int);
};
class Point2D : public Point //derived, child, subclass
{
protected:
int y;
public:
Point2D(int =0, int =0);
~Point2D();
int getY() { return y; }
void setY(int);
void setX(int);
void setXY(int, int);
Point2D operator+(Point2D);
};
class Point3D : public Point2D
{
};
/*
class Point2D : public Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - public
class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected
class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private
*/
#endif // POINT_H_INCLUDED
> point.cpp
#include
#include "point.h"
using namespace std;
Point::Point(int x)
{
this->x = x;
cout « “The constructor from the Point class has just been invoked” « endl;
}
Point::~Point()
{
cout « “The destructor from the Point class has just been invoked” « endl;
}
void Point::setX(int x)
{
this->x = x;
cout « “Im from Point” « endl;
}
Point2D::Point2D(int x, int y) : Point(x)
{
this->y = y;
cout « “The constructor from the Point2D class has just been invoked” « endl;
}
Point2D::~Point2D()
{
cout « “The destructor from the Point2D class has just been invoked” « endl;
}
void Point2D::setY(int y)
{
this->y = y;
}
void Point2D::setXY(int x, int y)
{
setX(x);
setY(y);
}
void Point2D::setX(int x)
{
this->x = x;
cout « “Im from Point2D” « endl;
}
Point2D Point2D::operator+(Point2D o)
{
Point2D tmp;
tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());
return tmp; } ```
Templates
- 템플릿(template)이란 매개변수의 타입에 따라 함수나 클래스를 생성하는 메커니즘을 의미합니다.
- 템플릿은 타입이 매개변수에 의해 표현되므로, 매개변수화 타입(parameterized type)이라고도 불립니다
- 템플릿을 사용하면 타입마다 별도의 함수나 클래스를 만들지 않고, 여러 타입에서 동작할 수 있는 단 하나의 함수나 클래스를 작성하는 것이 가능합니다.
2. Function Template(함수 템플릿)
- C++에서 함수 템플릿(function template)이란 함수의 일반화된 선언을 의미합니다
- 함수 템플릿을 사용하면 같은 알고리즘을 기반으로 하면서, 서로 다른 타입에서 동작하는 함수를 한 번에 정의할 수 있습니다.
- 임의의 타입으로 작성된 함수에 특정 타입을 매개변수로 전달하면, C++ 컴파일러는 해당 타입에 맞는 함수를 생성해 줍니다
문법 ``` template
함수의 원형
{
// 함수의 본체
}
- 위에서 정의된 타입 이름은 함수의 원형과 본체에서 임의의 타입으로 사용할 수 있습니다
- **이렇게 정의된 함수 템플릿을 호출할 때 매개변수로 int형을 전달하면, 함수의 원형과 본체에서 정의된 타입 이름은 모두 int형으로 바뀌게 됩니다.**
> 예제
template
void Swap(T& a, T& b);
int main(void)
{
int c = 2, d = 3;
cout << "c : " << c << ", d : " << d << endl;
Swap(c, d);
cout << "c : " << c << ", d : " << d << endl;
string e = "hong", f = "kim";
cout << "e : " << e << ", f : " << f << endl;
Swap(e, f);
cout << "e : " << e << ", f : " << f << endl;
return 0;
}
template
void Swap(T& a, T& b)
{
T temp;
temp = a;
a = b;
b = temp;
}
> 실행 결과
c : 2, d : 3
c : 3, d : 2
e : hong, f : kim
e : kim, f : hong
- 함수 템플릿이 각각의 타입에 대해 처음으로 호출될 때, C++ 컴파일러는 해당 타입의 인스턴스를 생성합니다.
- 이렇게 생성된 인스턴스는 해당 타입에 대해 특수화된 템플릿 함수입니다.
- 이 인스턴스는 함수 템플릿에 해당 타입이 사용될 때마다 호출됩니다.
## 3. 명시적 특수화(explicit specialization)
- C++의 함수 템플릿은 특정 타입에 대한 명시적 특수화를 제공하여, 해당 타입에 대해 특별한 동작을 정의할 수 있게 해줍니다.
- 컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 템플릿을 찾지 않고 해당 정의를 사용합니다.
- 앞서 정의된 함수 템플릿 Swap의 double형에 대한 명시적 특수화는 다음과 같습니다.
> 함수 템플릿 원형
template
void Swap(T& a, T& b);
template
> double형을 위한 명시적 특수화
template <> void Swap
# [Typedef](https://wikidocs.net/419)
- typedef는 새로운 타입을 만드는 것이 아니라 타입의 새로운 별칭을 정의하는 키워드 입니다
typedef int TypedefInt; TypedefInt a;
- 이 키워드가 템플릿과 무슨 관계인지 설명하겠습니다
- typedef는 클래스 안에서 타입의 새로운 별칭을 지을 수 있습니다
class MyTypeClass { public: typedef int Type1; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; return 0; }
- a는 MyTypeClass의 객체, b는 int 변수
class MyTypeClass { public: typedef int Type1; private: typedef double Type2; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; MyTypeClass::Type2 c; //에러 return 0; }
class MyTypeClass { public: typedef int Type1; void f() { Type2 c; } private: typedef double Type2; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; return 0; }
- typedef은 클래스 안에서도 타입의 별칭을 만들 수 있을 뿐 아니라 외부접근 제한 까지 영향을 받습니다.
- typedef는 템플릿 파라미터로 받은 데이터 타입이 필요할 때가 있습니다
#include
template
- 이렇게 타입안에 타입의 객체를 호출 할 수 있습니다. **이렇게 템플릿 매개변수에 종속된 것을 의존 이름(dependent name)** 이라고 합니다
- 클래스안에 중첩된 경우가 있는데 **중첩 의존 이름(nested dependent name)** 이라고 합니다.
- 확히 하면 클래스 안에 TempType 이라는 타입이 있으니까 **중첩 의존 타입 이름(nested dependent type name)** 이라고 합니다.
# Exercise 1
> main.cpp
#include
using namespace std; /* function templates generalization*/
void operationOnPoints();
template<typename T, typename T2> T add(T var1, T2 var2) { return var1 + var2; } /* template<> Point2D add(Point2D var1, Point2D var2) { Point2D tmp;
tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());
return tmp; } */ typedef Point<int> PointInt; int main() {
operationOnPoints();
//cout << add<double, double>(2, 5.6) << endl;
// cout « static_cast
return 0; } void operationOnPoints() { // PointInt a(5);
Point<int*> b(49);
//cout << a.getX() << endl;
//cout << b.getX() << endl; }
> point.h
#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED
#include
using namespace std;
template
template
template
};
template
tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());
return tmp; } /* class Point3D : public Point2D {
}; */
template<>
class Point
class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected
class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private
*/ #endif // POINT_H_INCLUDED
# Exercise 2
> main.cpp
#include
using namespace std; /* function templates generalization*/
void operationOnPoints();
template<typename T, typename T2> T add(T var1, T2 var2) { return var1 + var2; } /* template<> Point2D add(Point2D var1, Point2D var2) { Point2D tmp;
tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());
return tmp; } */ int main() {
operationOnPoints();
//cout << add<double, double>(2, 5.6) << endl;
// cout « static_cast
return 0; } void operationOnPoints() {
Point2D p1(10, 67);
Point2D p2(50, 3); // 60,70
Point2D sum = add(p1,p2);
cout << sum.getX() << endl;
cout << sum.getY() << endl;
}
> point.h
#ifndef POINT_H_INCLUDED #define POINT_H_INCLUDED
class Point //base, parent, superclass { protected: int x; public: Point(int =0); ~Point(); int getX() { return x; } void setX(int); }; class Point2D : public Point //derived, child, subclass { protected: int y; public: Point2D(int =0, int =0); ~Point2D(); int getY() { return y; } void setY(int); void setX(int); void setXY(int, int); Point2D operator+(Point2D);
}; class Point3D : public Point2D {
};
/* class Point2D : public Point everything what is inside Point (excluding constructor and destructor) will be in Point2D private - CANNOT ACCESS protected - protected public - public
class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected
class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private
*/ #endif // POINT_H_INCLUDED
> point.cpp
#include
using namespace std;
Point::Point(int x) { this->x = x; cout « “The constructor from the Point class has just been invoked” « endl; } Point::~Point() { cout « “The destructor from the Point class has just been invoked” « endl; } void Point::setX(int x) { this->x = x; cout « “Im from Point” « endl; }
Point2D::Point2D(int x, int y) : Point(x) { this->y = y; cout « “The constructor from the Point2D class has just been invoked” « endl; } Point2D::~Point2D() { cout « “The destructor from the Point2D class has just been invoked” « endl; }
void Point2D::setY(int y) { this->y = y; } void Point2D::setXY(int x, int y) { setX(x); setY(y); } void Point2D::setX(int x) { this->x = x; cout « “Im from Point2D” « endl; } Point2D Point2D::operator+(Point2D o) { Point2D tmp;
tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());
return tmp; } ```
Comments