C++ 과부하 해결
-
09-06-2019 - |
문제
이 질문에는 이미 답변이 있습니다.
다음 예에서 다음 명령문을 명시적으로 사용해야 하는 이유는 무엇입니까? b->A::DoSomething()
그냥보다는 b->DoSomething()
?
컴파일러의 오버로드 해결이 내가 말하는 방법이 무엇인지 알아내면 안 됩니까?
저는 마이크로소프트 VS 2005를 사용하고 있습니다.(메모:이 경우 가상을 사용하는 것은 도움이 되지 않습니다.)
class A
{
public:
int DoSomething() {return 0;};
};
class B : public A
{
public:
int DoSomething(int x) {return 1;};
};
int main()
{
B* b = new B();
b->A::DoSomething(); //Why this?
//b->DoSomething(); //Why not this? (Gives compiler error.)
delete b;
return 0;
}
해결책
두 개의 "오버로드"는 동일한 범위에 있지 않습니다.기본적으로 컴파일러는 일치하는 이름을 찾을 때까지 가능한 가장 작은 이름 범위만 고려합니다.인수 일치가 완료되었습니다. 나중에.귀하의 경우 이는 컴파일러가 B::DoSomething
.그런 다음 인수 목록과 일치하려고 시도하지만 실패합니다.
한 가지 해결책은 A
~ 안으로 B
범위:
class B : public A {
public:
using A::DoSomething;
// …
}
다른 팁
오버로드 해결은 C++의 가장 추악한 부분 중 하나입니다.
기본적으로 컴파일러는 B 범위에서 이름 일치 "DoSomething(int)"를 찾고 매개 변수가 일치하지 않는 것을 확인하고 오류와 함께 중지합니다.
이는 클래스 B의 A::DoSomething을 사용하여 극복할 수 있습니다.
class A
{
public:
int DoSomething() {return 0;}
};
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;}
};
int main(int argc, char** argv)
{
B* b = new B();
// b->A::DoSomething(); // still works, but...
b->DoSomething(); // works now too
delete b;
return 0;
}
아니요, 이 동작은 실수로 먼 기본 클래스에서 상속받는 일이 발생하지 않도록 하기 위해 존재합니다.
이 문제를 해결하려면 B 클래스에 A::DoSomething을 사용하여 호출하려는 메서드를 컴파일러에 알려야 합니다.
보다 이 기사 이 동작에 대한 빠르고 쉬운 개요를 확인하세요.
파생 클래스에 메서드가 있으면 기본 클래스에서 매개 변수에 관계없이 동일한 이름을 가진 모든 메서드가 숨겨집니다.이는 다음과 같은 문제를 피하기 위해 수행됩니다.
class A {} ;
class B :public A
{
void DoSomething(long) {...}
}
B b;
b.DoSomething(1); // calls B::DoSomething((long)1));
나중에 누군가 클래스 A를 변경합니다.
class A
{
void DoSomething(int ) {...}
}
지금 갑자기:
B b;
b.DoSomething(1); // calls A::DoSomething(1);
즉, 이렇게 작동하지 않으면 제어할 수 없는 클래스(A)에서 관련 없는 변경이 코드 작동 방식에 조용히 영향을 미칠 수 있습니다.
이는 이름 확인이 작동하는 방식과 관련이 있습니다.기본적으로 먼저 이름이 나오는 범위를 찾은 다음 해당 범위에서 해당 이름에 대한 모든 오버로드를 수집합니다.그러나 귀하의 경우 범위는 클래스 B이고 클래스 B에서는 B::DoSomething입니다. 숨기다 A::D뭔가:
3.3.7 이름 숨기기 [basic.scope.hiding]
...[한조각]...
3 멤버 기능 정의에서 로컬 이름 선언은 동일한 이름의 클래스 구성원의 선언을 숨 깁니다.보다 기본.범위.클래스.파생 클래스에서 회원의 선언 (클래스.파생) 동일한 이름의 기본 클래스 구성원의 선언을 숨 깁니다.보다 클래스.멤버.조회.
이름 숨김으로 인해 A::DoSomething은 오버로드 해결에도 고려되지 않습니다.
파생 클래스에서 함수를 정의하면 기본 클래스에서 해당 이름을 가진 모든 함수가 숨겨집니다.기본 클래스 함수가 가상이고 호환 가능한 서명이 있는 경우 파생 클래스 함수도 기본 클래스 함수를 재정의합니다.그러나 이는 가시성에 영향을 미치지 않습니다.
using 선언을 사용하여 기본 클래스 함수를 표시할 수 있습니다.
class B : public A
{
public:
int DoSomething(int x) {return 1;};
using A::DoSomething;
};
과부하가 아닙니다!그게 숨어 있어요!
사용할 함수에 대한 상속 트리를 검색할 때 C++는 인수 없이 이름을 사용하고 일단 정의를 찾으면 중지한 다음 인수를 검사합니다.주어진 예에서는 클래스 B에서 중지됩니다.원하는 작업을 수행하려면 클래스 B를 다음과 같이 정의해야 합니다.
class B : public A
{
public:
using A::DoSomething;
int DoSomething(int x) {return 1;};
};
함수는 하위 클래스에서 이름이 같지만 서명이 다른 함수에 의해 숨겨집니다.A::DoSomething();을 사용하는 것처럼 using 문을 사용하여 숨기기를 해제할 수 있습니다.