티스토리 뷰

오버라이딩과 오버로딩은 객체 지향 프로그래밍에서 중요한 개념이지만, 종종 혼동되는 경우가 많습니다. 이 글에서는 두 개념의 정의와 차이점을 핵심 내용과 함께 심층적으로 분석하고, 각 차이점과 관련된 코드 예시와 주의 사항을 제공합니다.

1. 개념 및 기본 사용법

오버라이딩:

  • 상속 관계에서 하위 클래스가 상위 클래스의 메소드를 재정의하는 것을 의미합니다.
  • 하위 클래스는 상위 클래스의 메소드 구현을 변경하거나 확장하여 특정 상황에 맞게 사용할 수 있습니다.
  • 메소드 이름, 반환 타입, 매개변수 목록이 완전히 동일해야 합니다.

오버로딩:

  • 같은 클래스 내에서 같은 이름의 메소드를 여러 개 정의하는 것을 의미합니다.
  • 각 메소드는 매개변수 목록 (갯수, 타입, 순서)에 따라 구별됩니다.
  • 메소드 이름이 동일하더라도 매개변수 목록이 서로 다르면 오버로딩이 발생합니다.
class Animal {
public:
  virtual void speak() = 0; // 순수 가상 메소드
};

class Dog : public Animal {
public:
  void speak() override { // 오버라이딩: Animal::speak() 재정의
    cout << "멍멍!" << endl;
  }
};

class Cat : public Animal {
public:
  void speak() override { // 오버라이딩: Animal::speak() 재정의
    cout << "야옹!" << endl;
  }
};

void printSound(Animal* animal) {
  animal->speak(); // 오버라이딩된 speak() 메소드 호출
}

int main() {
  Dog* dog = new Dog();
  Cat* cat = new Cat();

  printSound(dog); // "멍멍!" 출력
  printSound(cat); // "야옹!" 출력

  return 0;
}

 

2. 주요 차이점 심층 분석

2.1. 상속 관계:

오버라이딩:

  • 상속 관계에서만 발생합니다.
  • 하위 클래스는 상위 클래스의 메소드를 재정의하여 더 특화된 기능을 제공합니다.

오버로딩:

  • 상속 관계와 관련이 없습니다.
  • 같은 클래스 내에서 여러 메소드를 정의하여 다양한 기능을 제공합니다.
class Animal {
public:
  virtual void move() = 0; // 순수 가상 메소드
};

class Bird : public Animal {
public:
  void move() override { // 오버라이딩: Animal::move() 재정의
    cout << "날아다닙니다." << endl;
  }
};

class Fish : public Animal {
public:
  void move() override { // 오버라이딩: Animal::move() 재정의
    cout << "헤엄칩니다." << endl;
  }
};

int main() {
  Bird* bird = new Bird();
  Fish* fish = new Fish();

  bird->move(); // "날아다닙니다." 출력
  fish->move(); // "헤엄칩니다." 출력

  return 0;
}

2.2. 메소드 시그니처:

오버라이딩:

  • 메소드 이름, 반환 타입, 매개변수 목록이 완전히 동일해야 합니다.
  • 시그니처가 일치하지 않으면 오류가 발생합니다.

오버로딩:

  • 메소드 이름은 동일하지만 매개변수 목록 (갯수, 타입, 순서)에 따라 구별됩니다.
  • 시그니처가 서로 다르면 오버로딩이 발생합니다.

2.3. 동적 바인딩:

오버라이딩:

  • 동적 바인딩을 통해 상황에 맞는 메소드가 자동으로 호출됩니다.
  • 실행 시점에 객체의 실제 타입에 따라 메소드 호출이 결정됩니다.

오버로딩:

  • 동적 바인딩과 관련이 없습니다.
  • 컴파일 시점에 메소드 호출이 결정됩니다.
class Animal {
public:
  virtual void speak() = 0; // 순수 가상 메소드
};

class Dog : public Animal {
public:
  void speak() override { // 오버라이딩: Animal::speak() 재정의
    cout << "멍멍!" << endl;
  }
};

class Cat : public Animal {
public:
  void speak() override { // 오버라이딩: Animal::speak() 재정의
    cout << "야옹!" << endl;
  }
};

void printSound(Animal* animal) {
  animal->speak(); // 오버라이딩된 speak() 메소드 호출
}

int main() {
  Animal* animal1 = new Dog();
  Animal* animal2 = new Cat();

  printSound(animal1); // "멍멍!" 출력
  printSound(animal2); // "야옹!" 출력

  return 0;
}

2.4. 주의 사항

오버라이딩:

  • 상위 클래스의 메소드를 오버라이딩할 때는 메소드 시그니처를 정확하게 일치시켜야 합니다.
  • 오버라이딩된 메소드는 상위 클래스의 메소드와 동일하거나 더 강력한 기능을 제공해야 합니다.
  • 상위 클래스의 메소드를 오버라이딩하지 않을 경우 상속받은 메소드가 그대로 사용됩니다.

오버로딩:

  • 오버로딩된 메소드의 매개변수 목록은 명확하게 구별되어야 합니다.
  • 오버로딩된 메소드의 이름이 동일하더라도 매개변수 목록이 다르면 다른 메소드로 인식됩니다.
  • 오버로딩된 메소드를 사용할 때는 매개변수를 정확하게 입력해야 합니다.

3. 결론

오버라이딩과 오버로딩은 객체 지향 프로그래밍에서 중요한 개념입니다. 두 개념의 차이점을 명확하게 이해하고 상황에 맞게 적절하게 사용해야 코드의 효율성과 유지 관리성을 높일 수 있습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함