독서노트Effective_C++_약관 46: 유형 변환이 필요한 경우 템플릿에 비구성원 함수를 정의합니다.
13279 단어 effective
그래서 우리는 일반적으로 이를 우원 함수로 정의한다. 다음과 같다.
1 class Rational
2 {
3 private:
4 int numerator;
5 int denominator;
6 public:
7 Rational(int n = 0, int d = 1): numerator(n), denominator(d){assert(denominator != 0);}
8 int GetNumerator() const{return numerator;}
9 int GetDenominator() const {return denominator;}
10 friend const Rational operator* (const Rational& r1, const Rational& r2);
11 };
12 const Rational operator* (const Rational& r1, const Rational& r2)
13 {
14 return Rational(r1.numerator * r2.numerator, r1.denominator * r2.denominator);
15 }
이제 템플릿을 도입합니다. 아래와 같이 쓸 수 있습니다. 여기의operator*는 독립된 템플릿 함수입니다.
1 template <class T>
2 class Rational
3 {
4 private:
5 T Numerator;
6 T Denominator;
7
8 public:
9 Rational(const T& Num = 0, const T& Den = 1) : Numerator(Num), Denominator(Den){}
10 const T GetNumerator() const
11 {
12 return Numerator;
13 }
14
15 const T GetDenominator() const
16 {
17 return Denominator;
18 }
19
20 string ToString() const
21 {
22 stringstream ss;
23 ss << Numerator << "/" << Denominator;
24 return ss.str();
25 }
26 };
27
28 template <class T>
29 const Rational<T> operator* (const Rational<T>& a, const Rational<T>& b)
30 {
31 return Rational<T>(a.GetNumerator() * b.GetNumerator(),
32 a.GetDenominator() * b.GetDenominator() );
33 }
그러나 다음main 함수의 두 줄은 컴파일을 통과할 수 없습니다.
1 int main()
2 {
3 Rational<int> a(3, 5);
4 Rational<int> c = a * 2; // !
5 c = 2 * a; // !
6 cout << c.ToString() << endl;
7 }
왜냐하면 컴파일러가 T를 유도하는 데 어려움이 생겼기 때문이다. a*2는 컴파일러가 보기에 a는 Rational
문제를 해결하는 사고방식이 이어서 생겼다. 컴파일러가 이 두 과정을 동시에 받아들일 수 없으니 미리 한 조건을 충족시키고 컴파일러가 다른 과정을 집행하도록 하자.
이operator*를templateclass에 넣으면 템플릿 클래스를 만드는 단계에서 T를 정합니다. 그러면 컴파일러가 스텔스 변환을 실행하면 됩니다.
그래서 우리는 이렇게 고칠 수 있다.
1 template <class T>
2 class Rational
3 {
4 …
5 friend Rational operator* (const Rational& a, const Rational& b); 6 };
7
8 template <class T>
9 const Rational<T> operator* (const Rational<T>& a, const Rational<T>& b)
10 {
11 // ,
12 return Rational<T>(a.GetNumerator() * b.GetNumerator(),
13 a.GetDenominator() * b.GetDenominator() );
14 }
빨간색 부분에 주의하여 우리는 유원 함수의 성명을 추가했는데 과연 번역이 통과되었지만 링크를 잘못 보고했다. 왜냐하면 링크기가operator*의 정의를 찾지 못했기 때문이다. 여기서 템플릿 클래스의 특수한 상황을 말하고자 한다. 이것은 일반적인 클래스와 다르다. 템플릿 클래스의 유원 함수는 클래스에서만 실현될 수 있기 때문에 함수체 부분을 클래스로 옮겨야 한다. 다음과 같다.
1 template <class T>
2 class Rational
3 {
4 …
5 friend Rational operator* (const Rational& a, const Rational& b)
6 {
7 return Rational (a.GetNumerator() * b.GetNumerator(),
8 a.GetDenominator() * b.GetDenominator());
9 }
10 …
11 }
이제 컴파일링과 링크에 문제가 없습니다.여기서 다시 한 번 말하자면 클래스 안으로 이동한 후에 T의 표지부는 쓰지 않아도 되지만 굳이 아래와 같이 써야 한다면 자연히 OK이다.
1 friend Rational<T> operator* (const Rational<T>& a, const Rational<T>& b)
2 {
3 return Rational<T>(a.GetNumerator() * b.GetNumerator(),
4 a.GetDenominator() * b.GetDenominator());
5 }
operator*에는 단지 한 마디가 있지만 friend 함수에 너무 많은 것이 있으면 보조 방법을 정의할 수 있다. 예를 들어DoMultiply(), 이DoMultiply는 클래스 밖으로 놓아서 실현할 수 있다. DoMultiply 자체는 혼합 곱셈(2*SomeRational 또는SomeRational*2)을 지원하지 않지만 Operator*에서 이미 은밀한 유형 전환이 진행되었기 때문에DoMultiply라는 단계는 문제가 없다.
마지막으로 요약:
"class template를 작성할 때,"이template와 관련된 "함수가"모든 매개 변수의 은밀한 형식 변환 "을 지원할 때, 그 함수를"class template 내부의friend 함수 "로 정의하십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[JPA] 연관 관계 매핑 ( 양방향 )기존에 소스는 Member -> Team 으로만 단방향 매핑을 하였기 때문에 Member만이 Team을 알 수 있었습니다. 따라서 mappedBy="team"을 설정 함으로써 Member.team과 연관관계를 맺게됩...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.