Java 상속의 특징 (C++과 비교하여)

Jeongbeen Lee·2025년 1월 13일

TechTalk

목록 보기
2/4

Java 상속의 특징

Java 클래스에서는 단일 상속만 지원한다. 이 말은 하나의 클래스는 하나의 부모 클래스만 상속받을 수 있다는 의미이다.

class Parent { }
class Child extends Parent { } // 가능

class Parent1 { }
class Parent2 { }
class Child extends Parent1, Parent2 { } // 컴파일 오류

여기서 궁금증이 생긴다. 왜 Java는 단일 상속만 지원하며 이로 인해 생기는 불편한 점을 어떻게 해결할까? 먼저 C++에서 상속을 어떻게 처리하는지 보자.

C++의 다중 상속

C++은 다중 상속을 지원하여 하나의 클래스가 두 개 이상의 부모 클래스로부터 상속을 받을 수 있다.

class Parent1 {
public:
    void method1() {
        std::cout << "Method from Parent1" << std::endl;
    }
};

class Parent2 {
public:
    void method2() {
        std::cout << "Method from Parent2" << std::endl;
    }
};

class Child : public Parent1, public Parent2 {
};

int main() {
    Child child;
    child.method1(); // Parent1의 메서드 호출
    child.method2(); // Parent2의 메서드 호출
    return 0;
}

이렇게 보기엔 별 문제가 없을 수 있지만, 다중 상속은 두 가지의 문제를 발생시킨다.

1. 다이아몬드 문제

만약 두 부모 클래스가 공통의 조상을 가질 때, 자식 클래스는 해당 조상의 멤버를 여러 번 상속받게 된다.

class Grandparent {
public:
    void display() {
        std::cout << "Grandparent" << std::endl;
    }
};

class Parent1 : public Grandparent {};
class Parent2 : public Grandparent {};

class Child : public Parent1, public Parent2 {};

int main() {
    Child child;
    // child.display(); // 오류: display()가 두 번 상속되어 모호성 발생
}

C++에서는 이 문제를 virtual 키워드를 사용하여 해결한다.

class Grandparent {
public:
    void display() {
        std::cout << "Grandparent" << std::endl;
    }
};

class Parent1 : virtual public Grandparent {};
class Parent2 : virtual public Grandparent {};

class Child : public Parent1, public Parent2 {};

int main() {
    Child child;
    child.display(); // 정상 작동
    return 0;
}

virtual 키워드를 사용하면 공통된 조상을 하나만 상속받도록 설정할 수 있다.

2. 함수 이름의 모호성

만약 Parent1 클래스와 Parent2 클래스에 동일한 이름의 메서드가 있다면, 자식 클래스 입장에선 어떤 메서드를 호출해야 할지 모호하다.

int main() {
    Child child;
    child.Parent1::display(); // Parent1의 display() 호출
    child.Parent2::display(); // Parent2의 display() 호출
}

c++에서는 이렇게 메서드 앞에 클래스의 범위를 지정해주어 이 문제를 해결한다.

추가로, Python 역시 다중 상속을 지원하는데, 이 문제를 메서드 결정 순서(MRO: Method Resolution Order)를 통해 범위지정 없이 모호성을 해결한다.

두 해결 방법 모두 코드의 복잡성을 증가시키고 부모 클래스에서 변경사항 발생 시 해당 코드들도 모두 확인해주어야 해서 유지보수성을 떨어트린다.

Java의 단일 상속의 이유

단일 상속의 제한은 위와 같은 문제들을 원천적으로 차단할 수 있다. 다중 상속을 사용하지 못함으로써 생기는 불편함은 인터페이스의 사용으로 어느정도 해결할 수 있다. 인터페이스는 여러 개 구현 가능하면서도 충돌을 방지할 수 있다.

인터페이스의 특징

인터페이스는 구현이 없는 메서드들로 구성되어 있어 같은 이름의 메서드가 존재하더라도 자식 클래스는 해당 메서드를 직접 구현해야 하므로 충돌이 발생하지 않는다. 이와 같은 이유로, Java에서는 인터페이스 사이에서는 다중 상속이 가능하다.

interface Interface1 {
    void method();
}

interface Interface2 {
    void method();
}

class MyClass implements Interface1, Interface2 {
    @Override
    public void method() {
        System.out.println("Implementation of method");
    }
}

Java는 인터페이스를 사용하여 하나의 클래스가 여러 타입으로 동작할 수 있게 하며 이것은 다형성을 활용한 객체지향 설계를 가능하게 한다.

1개의 댓글

comment-user-thumbnail
2025년 1월 13일

C++이 익숙하진 않아서 그런지 상속관계에 대한 내용이 어렵지만 흥미롭네요

답글 달기