Project Hub

7. 이항 연산자 오버로딩 본문

C++/c++ basic

7. 이항 연산자 오버로딩

safy 2022. 12. 21. 13:39
728x90
반응형

이전 글

2022.12.21 - [C++/c++ basic] - 6. Wrapper 클래스 - 타입변환 연산자

 

6. Wrapper 클래스 - 타입변환 연산자

이전 글 & 참고 글 2022.12.21 - [분류 전체보기] - 5. 연산자 오버로딩, friend 키워드 5. 연산자 오버로딩, friend 키워드 이전 글 2022.12.21 - [C++/c++ basic] - 4. implicit, explicit, mutable 키워드 4. implicit, explicit, m

projecthub.tistory.com

참고 글

2022.12.21 - [C++/c++ basic] - 5. 연산자 오버로딩, friend 키워드

 

5. 연산자 오버로딩, friend 키워드

이전 글 2022.12.21 - [C++/c++ basic] - 4. implicit, explicit, mutable 키워드 4. implicit, explicit, mutable 키워드 이전 글 2022.12.21 - [C++/c++ basic] - 3. copy consturctor 3. copy consturctor 이전 글 2022.12.21 - [C++/c++ basic] - 2. refer

projecthub.tistory.com

 

이항 연산자

우선, 아래와 같은 코드가 있다고 생각해보자.

#pragma once
#include <iostream>
 
class CComplex
{
public:
    CComplex(double dReal, double dImg) : m_dReal(dReal), m_dImg(dImg) {};
    CComplex(const char* pszString);
    ~CComplex();
 
    // a = b + c + b 일 경우, &로 반환하면 첫번째 b + c를 수행하면, b의 값이 변경된다.
    // 따라서 Complex& 형태가 아니라 Complex 형태로 반환을 하여 값을 리턴하도록 한다.
    CComplex operator+(const CComplex& Complex) const;
    CComplex operator-(const CComplex& Complex) const;
    CComplex operator*(const CComplex& Complex) const;
    CComplex operator/(const CComplex& Complex) const;
 
    CComplex& operator=(const CComplex& Complex);
 
    double GetNumber(const char* pszString, int iStart, int iEnd) const;
 
    void println() { std::cout << "( " << m_dReal << ", " << m_dImg << " )" << std::endl; }
 
private:
    double m_dReal;
    double m_dImg;
};
 
CComplex::CComplex(const char* pszString)
{
    int iIpos = -1;
 
    m_dReal = 0.0;
    m_dImg = 0.0;
     
    for (int i = 0; i < strlen(pszString); i++)
    {
        if ('i' == pszString[i])
        {
            iIpos = i;
            break;
        }
    }
 
    if (-1 == iIpos)
    {
        m_dReal = GetNumber(pszString, 0, strlen(pszString) - 1);
    }
    else
    {
        m_dReal = GetNumber(pszString, 0, iIpos - 1);
        m_dImg = GetNumber(pszString, iIpos + 1, strlen(pszString) - 1);
    }
 
    if (-1 != iIpos && '-' == pszString[iIpos - 1])
        m_dImg += -1.0;
}
 
CComplex CComplex::operator+(const CComplex& Complex) const
{
    CComplex temp(m_dReal + Complex.m_dReal, m_dImg + Complex.m_dImg);
    return temp;
}
 
CComplex CComplex::operator-(const CComplex& Complex) const
{
    CComplex temp(m_dReal - Complex.m_dReal, m_dImg - Complex.m_dImg);
    return temp;
}
 
CComplex CComplex::operator*(const CComplex& Complex) const
{
    CComplex temp((m_dReal * Complex.m_dReal) - (m_dImg * Complex.m_dImg),
        (m_dReal * Complex.m_dImg) - (m_dImg * Complex.m_dReal));
    return temp;
}
 
CComplex CComplex::operator/(const CComplex& Complex) const
{
    CComplex temp((m_dReal * Complex.m_dReal) + (m_dImg * Complex.m_dImg) / (Complex.m_dReal * Complex.m_dReal) + (Complex.m_dImg * Complex.m_dImg),
        (m_dImg * Complex.m_dReal) - (m_dReal * Complex.m_dImg) / (Complex.m_dReal * Complex.m_dReal) + (Complex.m_dImg * Complex.m_dImg));
    return temp;
}
 
CComplex& CComplex::operator=(const CComplex& Complex)
{
    m_dReal = Complex.m_dReal;
    m_dImg = Complex.m_dImg;
 
    return *this;
}
 
double CComplex::GetNumber(const char* pszString, int iStart, int iEnd) const
{
    bool bIsMinus = false;
    int iDotPos = -1;
    double dNum = 0.0;
    double dDecimal = 1.0;
 
    if ('-' == pszString[iStart])
    {
        bIsMinus = true;
        iStart++;
    }
 
    for (int i = iStart; i <= iEnd; i++)
    {
        if ('.' == pszString[i])
        {
            iDotPos = i;
            break;
        }
    }
 
    for (int i = iStart; i < iDotPos; i++)
    {
        if (isdigit(pszString[i]))
            dNum += pszString[i] - '0';
    }
 
    for (int i = iDotPos + 1; i <= iEnd; i++)
    {
        if (isdigit(pszString[i]))
        {
            dDecimal /= 10.0;
            dNum += (pszString[i] - '0') * dDecimal;
        }
    }
         
    if (bIsMinus) dNum *= -1.0;
 
 
    return dNum;
}
 
int main()
{
    CComplex a(1.0, 1.0);
 
 
    a = a + "-1.0 + i3.923";
    a = "-1.0 + i3.923" + a;
 
    return 0;
}


main 함수에 보면,

a = a + "-1.0 + i3.923";
a = "-1.0 + i3.923" + a;

 

이렇게 두 가지가 정의되어 있다. 보면, 같은 결과를 반환하는 것 같지만, 그렇지 않다. 

아래의 경우에는 컴파일 되지 않는다. 

이유는 다음과 같다.

먼저 a = a + "-1.0 + i3.923"; 의 경우,
 
1. a.operator+("-1.0 + i3.923") 으로 처리됨 (operator+(const char* pszString)가 없어도, implicit 로 인해 const char* 에서 CComplex 를 생성할 수 있는 생성자를 찾게되기 때문)
2. a.operator+(CComplex("3.0-i2.2324")); 으로 처리
 
와 같은 순서로 처리가 된다.
 
 
반면에 a = "-1.0 + i3.923" + a; 의 경우에는 이 같은 변형이 불가능하므로 컴파일 에러가 발생하게 된다.


이와 같은 문제를 해결하려면 어떻게 해야할까?

다행히도, 

 

컴파일러는 이항연산자 (피연산자를 두 개를 취하는 연산자들. +, -, *, /, = 등등)를 다음과 같이 두 개의 방식으로 처리한다.

임의의 연산자 @ 에 대해서, a@b 는
 
a.operator@(b);             -> operator@ 는 a 의 클래스의 멤버 함수로써 사용되는 것
operator@(a, b);            -> operator@ 는 클래스 외부에 정의되어 있는 일반적인 함수를 의미. 해당 함수는 정의가 필요하다.


두번째 방식을 처리하기 위해서는 해당 함수를 만들고, CComplex 클래스의 friend로 지정하면 된다.

class CComplex
{
    ...
    friend CComplex operator+(const CComplex& a, const CComplex& b);
};
 
CComplex operator+(const CComplex& a, const CComplex& b)
{
    CComplex temp(a.m_dReal + b.m_dReal, a.m_dImg + b.m_dImg);
    return temp;
}

 

위와 같은 함수를 추가하였다면, 컴파일 시 충돌 에러가 발생할 것이다.

이유는, 클래스 맴버 함수 중에 operator+가 존재하기 때문이다.

따라서 둘 중에 하나는 제거를 해주어야 한다. 

기준은, 

 

자기 자신을 리턴하는 이항 연산자일 경우(=, -=, = 등등) 멤버 함수로 설정을 하고, 

 

아닌 애들은( +, -, *, / 등등)외부 함수로 정의한다.

#pragma once
#include <iostream>
 
class CComplex
{
public:
    CComplex(double dReal, double dImg) : m_dReal(dReal), m_dImg(dImg) {};
    CComplex(const char* pszString);
    ~CComplex();
 
    CComplex& operator=(const CComplex& Complex);
 
    double GetNumber(const char* pszString, int iStart, int iEnd) const;
 
    void println() { std::cout << "( " << m_dReal << ", " << m_dImg << " )" << std::endl; }
     
    friend CComplex operator+(const CComplex& ComplexA, const CComplex& ComplexB);
 
private:
    double m_dReal;
    double m_dImg;
};
 
CComplex operator+(const CComplex& ComplexA, const CComplex& ComplexB)
{
    CComplex temp(ComplexA.m_dReal + ComplexB.m_dReal, ComplexA.m_dImg + ComplexB.m_dImg);
 
    return temp;
}
 
CComplex::CComplex(const char* pszString)
{
    int iIpos = -1;
 
    m_dReal = 0.0;
    m_dImg = 0.0;
     
    for (int i = 0; i < strlen(pszString); i++)
    {
        if ('i' == pszString[i])
        {
            iIpos = i;
            break;
        }
    }
 
    if (-1 == iIpos)
    {
        m_dReal = GetNumber(pszString, 0, strlen(pszString) - 1);
    }
    else
    {
        m_dReal = GetNumber(pszString, 0, iIpos - 1);
        m_dImg = GetNumber(pszString, iIpos + 1, strlen(pszString) - 1);
    }
 
    if (-1 != iIpos && '-' == pszString[iIpos - 1])
        m_dImg += -1.0;
}
 
CComplex& CComplex::operator=(const CComplex& Complex)
{
    m_dReal = Complex.m_dReal;
    m_dImg = Complex.m_dImg;
 
    return *this;
}
 
double CComplex::GetNumber(const char* pszString, int iStart, int iEnd) const
{
    bool bIsMinus = false;
    int iDotPos = -1;
    double dNum = 0.0;
    double dDecimal = 1.0;
 
    if ('-' == pszString[iStart])
    {
        bIsMinus = true;
        iStart++;
    }
 
    for (int i = iStart; i <= iEnd; i++)
    {
        if ('.' == pszString[i])
        {
            iDotPos = i;
            break;
        }
    }
 
    for (int i = iStart; i < iDotPos; i++)
    {
        if (isdigit(pszString[i]))
            dNum += pszString[i] - '0';
    }
 
    for (int i = iDotPos + 1; i <= iEnd; i++)
    {
        if (isdigit(pszString[i]))
        {
            dDecimal /= 10.0;
            dNum += (pszString[i] - '0') * dDecimal;
        }
    }
         
    if (bIsMinus) dNum *= -1.0;
 
 
    return dNum;
}
 
int main()
{
    CComplex a(1.0, 1.0);
 
 
    a = a + "-1.0 + i3.923";
    a = "-1.0 + i3.923" + a;
 
    return 0;
}



728x90
반응형
Comments