C++에서 이름 조회 순서는 이름 해결 규칙(name lookup)에 의해 규제되며, 이는 범위(scope), 숨김(hiding) 및 상속의 특성을 고려합니다. 주요 사항:
충돌 해결:
class Base { public: void foo(int) {} }; class Derived : public Base { public: using Base::foo; void foo(double) {} // 오버로드된 버전 };
Base::x 또는 Base::foo().다이아몬드 상속의 모호성 예:
struct A { int x; }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C { void test() { x = 42; } // OK: virtual 덕분에 x는 하나 };
기본 클래스에 메소드 foo(int)가 선언되고 파생 클래스에 foo(double)가 선언된 경우, 파생 클래스의 객체에서 foo(int)에 접근할 수 있습니까?
답변: 아니요, 메소드 foo(double)가 기본 클래스의 모든 오버로드된 버전을 "숨기고" 있습니다. foo(int)에 접근하려면 using Base::foo 또는 호출에서 Base::foo를 명시적으로 작성해야 합니다.
예:
class Base { public: void foo(int) { } }; class Derived : public Base { public: void foo(double) {} }; Derived d; d.foo(3); // 오류! foo(int)는 보이지 않음
사용:
class Derived : public Base { public: using Base::foo; void foo(double) {} }; d.foo(3); // 모든 것이 작동함
이야기
다중 상속 프로젝트에서 동일한 메소드를 가진 두 개의 기본 클래스로부터 상속받은 클래스가 생겼습니다. 저자들은 가상 상속을 사용하지 않았으며 기본 클래스의 두 개의 복사본이 생성되었습니다 — 모든 foo() 호출은 모호해졌고, 컴파일러는 코드를 컴파일하지 않았습니다. 이는 가상 상속을 적용하고 호출 시 Base::foo()를 명시함으로써 해결되었습니다.
이야기
그래픽 엔진에서 하나의 자식 클래스가 기본 클래스의 draw()에 대해 using을 사용하지 않고 자신의 draw()를 정의했습니다. 코드 리팩토링 후 잘못된 버전의 draw()가 호출되어 인터페이스의 일부가 그려지지 않았습니다. 이 오류는 클래스 구조를 깊이 있게 분석한 후에야 발견되었습니다.
이야기
새로운 컴파일러로 이동하면서 다중 및 가상 상속 시 이름의 모호성으로 인해 컴파일이 불가능해졌습니다. 이전에 작업했던 구현이 포함 체인의 차이를 고려하지 않았으며, 이는 번역 단위에서 서로 다른 이름 집합을 초래했습니다.