[C++] Operator Overloading & Class Keywords

choohaΒ·2026λ…„ 1μ›” 3일

C++

λͺ©λ‘ 보기
13/22

πŸ“š C++ ν•¨μˆ˜/μ—°μ‚°μž μ˜€λ²„λ‘œλ”©κ³Ό 클래슀 μ£Όμš” ν‚€μ›Œλ“œ

πŸ”Έ Function/Operator Overloading

Function Overloading (ν•¨μˆ˜ μ˜€λ²„λ‘œλ”©)

  • 같은 μ΄λ¦„μ˜ ν•¨μˆ˜λ₯Ό μ—¬λŸ¬ 개 μ •μ˜
  • λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ΄λ‚˜ κ°œμˆ˜κ°€ 달라야 함
  • Name Mangling: μ»΄νŒŒμΌλŸ¬κ°€ ν•¨μˆ˜ 이름에 νƒ€μž… 정보λ₯Ό μΆ”κ°€ν•˜μ—¬ ꡬ뢄
  • Static Polymorphism: 컴파일 νƒ€μž„μ— μ–΄λ–€ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν• μ§€ κ²°μ •
void print(int x) { std::cout << "int: " << x << std::endl; }
void print(double x) { std::cout << "double: " << x << std::endl; }
void print(std::string x) { std::cout << "string: " << x << std::endl; }

int main()
{
    print(10);        // print(int) 호좜
    print(3.14);      // print(double) 호좜
    print("hello");   // print(std::string) 호좜
    return 0;
}

Operator Overloading (μ—°μ‚°μž μ˜€λ²„λ‘œλ”©)

struct ComplexNum
{
    double real;
    double imag;
    
    ComplexNum(double r, double i) : real{r}, imag{i} {}
    
    void print() const
    {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};

// + μ—°μ‚°μž μ˜€λ²„λ‘œλ”© (μ „μ—­ ν•¨μˆ˜λ‘œ κ΅¬ν˜„)
ComplexNum operator+(const ComplexNum& lhs, const ComplexNum& rhs)
{
    return ComplexNum{lhs.real + rhs.real, lhs.imag + rhs.imag};
}

int main()
{
    ComplexNum c1{1, 1};
    ComplexNum c2{1, 2};
    
    ComplexNum c3 = c1 + c2;  // operator+(c1, c2) 호좜
    c3.print();  // 2 + 3i
    
    return 0;
}

멀버 ν•¨μˆ˜ vs μ „μ—­ ν•¨μˆ˜

// 멀버 ν•¨μˆ˜λ‘œ κ΅¬ν˜„
struct ComplexNum
{
    ComplexNum operator+(const ComplexNum& rhs) const
    {
        return ComplexNum{real + rhs.real, imag + rhs.imag};
    }
};
// c1 + c2 β†’ c1.operator+(c2)

// μ „μ—­ ν•¨μˆ˜λ‘œ κ΅¬ν˜„
ComplexNum operator+(const ComplexNum& lhs, const ComplexNum& rhs)
{
    return ComplexNum{lhs.real + rhs.real, lhs.imag + rhs.imag};
}
// c1 + c2 β†’ operator+(c1, c2)

μ „μ—­ ν•¨μˆ˜κ°€ ν•„μš”ν•œ 경우:

  • μ™Όμͺ½ ν”Όμ—°μ‚°μžκ°€ λ‹€λ₯Έ νƒ€μž…μΌ λ•Œ (예: 2 * complex)
  • λŒ€μΉ­μ μΈ 연산을 κ΅¬ν˜„ν•  λ•Œ

private 멀버 μ ‘κ·Ό 문제:

  • μ „μ—­ ν•¨μˆ˜λŠ” 클래슀의 private 멀버에 μ ‘κ·Όν•  수 μ—†μŒ
  • friend ν‚€μ›Œλ“œλ‘œ 접근을 ν—ˆμš©ν•  수 μžˆμ§€λ§Œ, μΊ‘μŠν™”λ₯Ό κΉ¨λœ¨λ¦¬λ―€λ‘œ ꢌμž₯ν•˜μ§€ μ•ŠμŒ
  • λŒ€μ‹  public getter ν•¨μˆ˜λ₯Ό μ œκ³΅ν•˜κ±°λ‚˜ 멀버λ₯Ό public으둜 λ§Œλ“œλŠ” 것이 μ’‹μŒ (κ°„λ‹¨ν•œ ꡬ쑰체의 경우)
// ❌ friend μ‚¬μš© (μΊ‘μŠν™” μœ„λ°˜)
class ComplexNum {
    double real;
    double imag;
    friend ComplexNum operator+(const ComplexNum&, const ComplexNum&);
};

// βœ… public 멀버 λ˜λŠ” getter μ‚¬μš©
struct ComplexNum {
    double real;  // κ°„λ‹¨ν•œ 데이터 κ΅¬μ‘°λŠ” public으둜
    double imag;
};
// λ˜λŠ”
class ComplexNum {
    double real;
    double imag;
public:
    double getReal() const { return real; }
    double getImag() const { return imag; }
};

πŸ”Έ Class κ΄€λ ¨ ν‚€μ›Œλ“œ

const (멀버 ν•¨μˆ˜)

class Cat
{
    std::string mName;
    int mAge;
    
public:
    // const 멀버 ν•¨μˆ˜: 객체의 μƒνƒœλ₯Ό λ³€κ²½ν•˜μ§€ μ•ŠμŒ
    void print() const
    {
        std::cout << mName << " " << mAge << std::endl;
        // mAge = 10;  // ❌ 컴파일 μ—λŸ¬!
    }
    
    std::string getName() const { return mName; }  // βœ… OK
    
    void setAge(int age) { mAge = age; }  // non-const ν•¨μˆ˜
};

int main()
{
    const Cat kitty{"kitty", 1};
    kitty.print();      // βœ… OK (const ν•¨μˆ˜)
    kitty.getName();    // βœ… OK (const ν•¨μˆ˜)
    kitty.setAge(2);    // ❌ 컴파일 μ—λŸ¬! (non-const ν•¨μˆ˜)
    return 0;
}

mutable (κ°€λ³€ 멀버 λ³€μˆ˜)

  • const 멀버 ν•¨μˆ˜ λ‚΄μ—μ„œλ„ μˆ˜μ • κ°€λŠ₯ν•œ 멀버 λ³€μˆ˜
  • 주둜 캐싱, 톡계, 디버깅 정보 등에 μ‚¬μš©
  • λ‚¨μš©ν•˜λ©΄ const의 μ˜λ―Έκ°€ ν‡΄μƒ‰λ˜λ―€λ‘œ μ‹ μ€‘ν•˜κ²Œ μ‚¬μš©
class Cat
{
    std::string mName;
    mutable int mCallCount;  // mutable 멀버
    
public:
    Cat(std::string name) : mName{std::move(name)}, mCallCount{0} {}
    
    std::string getName() const
    {
        mCallCount++;  // βœ… const ν•¨μˆ˜μ§€λ§Œ μˆ˜μ • κ°€λŠ₯
        return mName;
    }
    
    int getCallCount() const { return mCallCount; }
};

int main()
{
    const Cat kitty{"kitty"};
    kitty.getName();
    kitty.getName();
    std::cout << kitty.getCallCount();  // 2
    return 0;
}

explicit (λͺ…μ‹œμ  λ³€ν™˜)

  • 암묡적 νƒ€μž… λ³€ν™˜(Implicit Conversion)을 λ°©μ§€
  • 주둜 단일 λ§€κ°œλ³€μˆ˜ μƒμ„±μžμ— μ‚¬μš©

Implicit Conversion 문제 상황

class Cat
{
    int mAge;
    
public:
    Cat(int age) : mAge{age} {}  // 단일 λ§€κ°œλ³€μˆ˜ μƒμ„±μž
};

void func(Cat cat) { /* ... */ }

int main()
{
    Cat kitty = 3;      // βœ… Cat(3)으둜 암묡적 λ³€ν™˜
    func(5);            // βœ… Cat(5)둜 암묡적 λ³€ν™˜
    // μ˜λ„ν•˜μ§€ μ•Šμ€ λ³€ν™˜μ΄ λ°œμƒν•  수 있음!
    return 0;
}

explicit으둜 ν•΄κ²°

class Cat
{
    int mAge;
    
public:
    explicit Cat(int age) : mAge{age} {}  // explicit ν‚€μ›Œλ“œ
};

int main()
{
    Cat kitty = 3;      // ❌ 컴파일 μ—λŸ¬!
    Cat kitty{3};       // βœ… OK (λͺ…μ‹œμ  생성)
    Cat kitty(3);       // βœ… OK (λͺ…μ‹œμ  생성)
    
    func(5);            // ❌ 컴파일 μ—λŸ¬!
    func(Cat{5});       // βœ… OK (λͺ…μ‹œμ  생성)
    
    return 0;
}

explicit μ‚¬μš© κ°€μ΄λ“œλΌμΈ

  • 단일 λ§€κ°œλ³€μˆ˜ μƒμ„±μžλŠ” 거의 항상 explicit을 λΆ™μ΄λŠ” 것이 μ’‹μŒ
  • μ˜λ„μ μΈ 암묡적 λ³€ν™˜μ΄ ν•„μš”ν•œ 경우만 μƒλž΅ (예: wrapper 클래슀)
  • C++11λΆ€ν„°λŠ” μ—¬λŸ¬ λ§€κ°œλ³€μˆ˜ μƒμ„±μžμ—λ„ μ‚¬μš© κ°€λŠ₯
class Vector
{
public:
    explicit Vector(int size) {}           // βœ… explicit ꢌμž₯
    Vector(int x, int y, int z) {}         // μ—¬λŸ¬ λ§€κ°œλ³€μˆ˜λŠ” 선택적
    explicit Vector(std::vector<int> v) {} // βœ… explicit ꢌμž₯
};

<참고 자료>

μ½”λ“œμ—†λŠ” ν”„λ‘œκ·Έλž˜λ°
C++ Operator Overloading

0개의 λŒ“κΈ€