태그 보관물: const-method

const-method

const가 아닌 메서드가 private 일 때 public const 메서드가 호출되지 않는 이유는 무엇입니까? << “non

이 코드를 고려하십시오.

struct A
{
    void foo() const
    {
        std::cout << "const" << std::endl;
    }

    private:

        void foo()
        {
            std::cout << "non - const" << std::endl;
        }
};

int main()
{
    A a;
    a.foo();
}

컴파일러 오류는 다음과 같습니다.

오류 : ‘void A :: foo ()’는 비공개입니다.

그러나 개인 정보를 삭제하면 작동합니다. const가 아닌 메서드가 private 일 때 public const 메서드가 호출되지 않는 이유는 무엇입니까?

즉, 액세스 제어보다 과부하 해결이 필요한 이유는 무엇입니까? 이건 이상해. 일관성이 있다고 생각하십니까? 내 코드가 작동하고 메서드를 추가하면 작업 코드가 전혀 컴파일되지 않습니다.



답변

를 호출 a.foo();하면 컴파일러는 사용하기에 가장 좋은 함수를 찾기 위해 오버로드 확인을 거칩니다. 과부하 세트를 빌드 할 때

void foo() const

void foo()

이제 a가 아니기 때문에 const상수가 아닌 버전이 가장 적합하므로 컴파일러는 void foo(). 그런 다음 액세스 제한이 적용되고 void foo()비공개 이므로 컴파일러 오류가 발생 합니다.

과부하 해결에서는 ‘사용 가능한 최상의 기능 찾기’가 아닙니다. ‘가장 좋은 기능을 찾아서 사용 해보자’입니다. 액세스 제한 또는 삭제로 인해 불가능한 경우 컴파일러 오류가 발생합니다.

즉, 액세스 제어보다 과부하 해결이 필요한 이유는 무엇입니까?

글쎄, 봅시다 :

struct Base
{
    void foo() { std::cout << "Base\n"; }
};

struct Derived : Base
{
    void foo() { std::cout << "Derived\n"; }
};

struct Foo
{
    void foo(Base * b) { b->foo(); }
private:
    void foo(Derived * d) { d->foo(); }
};

int main()
{
    Derived d;
    Foo f;
    f.foo(&d);
}

이제 내가 실제로 void foo(Derived * d)비공개 로 만들려는 것이 아니라고 가정 해 봅시다 . 액세스 제어가 먼저 발생하면이 프로그램이 컴파일되고 실행되고 Base인쇄됩니다. 이것은 대규모 코드베이스에서 추적하기가 매우 어려울 수 있습니다. 액세스 제어는 오버로드 해결 후에 이루어지기 때문에 호출하려는 함수를 호출 할 수 없다는 멋진 컴파일러 오류가 발생하고 버그를 훨씬 쉽게 찾을 수 있습니다.


답변

궁극적으로 이것은 과부하 해결을 수행 할 때 접근성을 고려해서는 안된다는 표준의 주장으로 귀결됩니다 . 이 주장은 [over.match] 절 3 에서 찾을 수 있습니다 .

… 과부하 해결이 성공하고 사용 가능한 컨텍스트에서 실행 가능한 최상의 함수에 액세스 할 수없는 경우 (Clause [class.access]) 프로그램은 잘못된 형식입니다.

또한 같은 섹션의 1 항에 있는 주석 :

[참고 : 과부하 해결에 의해 선택된 기능이 상황에 적합하다고 보장 할 수 없습니다. 함수의 접근성과 같은 다른 제한으로 인해 호출 컨텍스트에서 잘못된 형식을 사용할 수 있습니다. — 끝 참고]

그 이유는 몇 가지 가능한 동기를 생각할 수 있습니다.

  1. 오버로드 후보의 접근성 변경으로 인한 예기치 않은 동작 변경을 방지합니다 (대신 컴파일 오류가 발생 함).
  2. 오버로드 해결 프로세스에서 컨텍스트 의존성을 제거합니다 (즉, 오버로드 해결은 클래스 내부 또는 외부에서 동일한 결과를 나타냄).

답변

액세스 제어가 과부하 해결 전에 왔다고 가정합니다. 사실상 이것은 public/protected/private접근성보다는 통제 된 가시성을 의미합니다 .

StroustrupDesign and Evolution of C ++ 의 섹션 2.10 에는 이에 대한 구절이 있으며 여기에서 다음 예제를 논의합니다.

int a; // global a

class X {
private:
    int a; // member X::a
};

class XX : public X {
    void f() { a = 1; } // which a?
};

스트로브 스트 룹은 현재의 규칙 (접근성 전에 가시성)의 혜택 (일시적으로)을 chaning이 있음을 언급 private내부 class Xpublic(예를 들어, 디버깅의 목적을 위해) 위의 프로그램의 의미에는 조용한 변화 (즉이 없다는 것입니다 X::a에 시도 두 경우 모두 액세스 할 수 있으며 위의 예에서 액세스 오류가 발생 함). 경우 public/protected/private가시성을 제어 할 프로그램의 의미는 (글로벌이 변경됩니다 a호출 할 것이다 private, 그렇지 않으면,X::a ).

그런 다음 그는 이것이 명시적인 설계에 의한 것인지 아니면 표준 C ++에 대한 Classess 이전 버전으로 C를 구현하는 데 사용 된 전 처리기 기술의 부작용인지 기억하지 못한다고 말합니다.

이것이 당신의 예와 어떤 관련이 있습니까? 기본적으로 표준에서 오버로드 확인을 만들었 기 때문에 이름 조회가 액세스 제어보다 먼저 발생한다는 일반적인 규칙을 준수합니다.

10.2 멤버 이름 조회 [class.member.lookup]

1 멤버 이름 조회는 클래스 범위 (3.3.7)에서 이름 (id-expression)의 의미를 결정합니다. 이름 조회로 인해 모호성이 발생할 수 있으며이 경우 프로그램의 형식이 잘못되었습니다. id-expression의 경우 이름 조회는 this의 클래스 범위에서 시작됩니다. 규정 된 ID의 경우 이름 조회는 nestedname- 지정자의 범위에서 시작됩니다. 이름 조회는 액세스 제어 전에 발생합니다 (3.4, 11 절).

8 오버로드 된 함수의 이름이 모호하지 않은 경우
액세스 제어 전에 오버로드 해결 (13.3)도 발생 합니다. 모호성은 종종 클래스 이름으로 이름을 한정하여 해결할 수 있습니다.


답변

암시 적 this포인터가 non- const이므로 컴파일러는 먼저 const버전 이전에 함수의 버전이 아닌지 여부를 확인합니다 const.

non- constone private을 명시 적으로 표시하면 해결이 실패하고 컴파일러는 검색을 계속하지 않습니다.


답변

일어나는 일의 순서를 명심하는 것이 중요합니다.

  1. 모든 실행 가능한 기능을 찾으십시오.
  2. 가장 실행 가능한 기능을 선택하십시오.
  3. 정확히 하나의 최상의 실행 가능한 함수가 없거나 실제로 최상의 실행 가능한 함수를 호출 할 수없는 경우 (액세스 위반 또는 deleted 인 함수로 인해 ) 실패합니다.

(3)은 (2) 이후에 발생합니다. 이것은 정말 중요합니다. 그렇지 않으면 함수를 deleted 또는 만들면 private무의미하고 추론하기가 훨씬 더 어려워지기 때문입니다.

이 경우 :

  1. 실행 가능한 기능은 A::foo()A::foo() const입니다.
  2. 가장 실행 가능한 기능은 A::foo()후자가 암시 적 this인수 에 대한 자격 변환을 포함하기 때문 입니다.
  3. 그러나 A::foo()이다 private당신은 그것을 액세스, 따라서 코드가 잘못 형성되어이 없습니다.

답변

이것은 C ++의 매우 기본적인 디자인 결정으로 귀결됩니다.

호출을 만족시키는 함수를 찾을 때 컴파일러는 다음과 같은 검색을 수행합니다.

  1. 해당 이름을 가진 무언가 가 있는 처음 1 개의 범위 를 찾기 위해 검색합니다 .

  2. 컴파일러는 해당 범위에서 해당 이름을 가진 모든 함수 (또는 펑터 등)를 찾습니다 .

  3. 그런 다음 컴파일러는 찾은 항목 중에서 가장 적합한 후보를 찾기 위해 오버로드 확인을 수행합니다 (액세스 가능 여부에 관계없이).

  4. 마지막으로 컴파일러는 선택한 함수에 액세스 할 수 있는지 확인합니다.

그 순서 때문에 액세스 할 수있는 다른 오버로드가 있더라도 컴파일러가 액세스 할 수없는 오버로드를 선택할 수 있습니다 (오버로드 해결 중에 선택되지 않음).

여부에 관해서는 될 사물을 다르게 할 : 예, 그것은 의심 할 여지없이 가능합니다. 그래도 C ++와는 확실히 다른 언어로 이어질 것입니다. 다소 사소 해 보이는 많은 결정은 처음에 명백한 것보다 훨씬 더 많은 영향을 미칠 수 있습니다.


  1. “First”는 그 자체로 약간 복잡 할 수 있습니다. 특히 템플릿이 포함 된 경우에는 2 단계 조회로 이어질 수 있기 때문에 검색을 수행 할 때 시작할 두 개의 완전히 분리 된 “루트”가 있습니다. 하지만 기본 아이디어는 매우 간단합니다. 가장 작은 둘러싸는 범위에서 시작하여 더 크고 더 큰 둘러싸는 범위로 나가십시오.

답변

액세스 제어 (public , protected, private) 해상도를 과부하에 영향을 미치지 않습니다. 컴파일러 void foo()는 가장 잘 일치 하기 때문에 선택합니다 . 접근 할 수 없다는 사실은 그것을 바꾸지 않습니다. 그것을 제거하면 void foo() const, 만 남게되며 , 이는 최상의 (즉, 유일한) 일치입니다.