수색…


소개

과부하 해결 에 관한 별도의 주제도 참조하십시오.

비고

모호성은 한 유형을 둘 이상의 유형으로 내재적으로 변환 할 수 있고 해당 유형에 대해 일치하는 기능이없는 경우 발생할 수 있습니다.

예 :

void foo(double, double);
void foo(long, long);

//Call foo with 2 ints
foo(1, 2); //Function call is ambiguous - int can be converted into a double/long at the same time 

함수 오버로딩이란 무엇입니까?

함수 오버로드는 동일한 이름을 가진 동일한 범위에서 선언 된 여러 기능들이 동의 인수를 의미하는 그들의 서명에 다른 (범위라고도 함) 같은 장소에 존재 데.

std::string 시작하는 일반화 된 인쇄 기능을위한 일련의 함수를 작성한다고 가정 std::string .

void print(const std::string &str)
{
    std::cout << "This is a string: " << str << std::endl;
}

이것은 잘 작동하지만, int 받아들이고 그것도 출력하는 함수를 원한다고 가정하십시오. 다음과 같이 작성할 수 있습니다.

void print_int(int num)
{
    std::cout << "This is an int:  " << num << std::endl;
}

그러나 두 함수가 다른 매개 변수를 받아들이 기 때문에 다음과 같이 작성할 수 있습니다.

void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}

이제 print 라는 이름의 두 가지 함수가 있지만 서명은 다릅니다. 하나는 std::string , 다른 하나는 int 받아 들인다. 이제는 다른 이름에 대해 걱정하지 않고 호출 할 수 있습니다.

print("Hello world!"); //prints "This is a string: Hello world!"
print(1337);           //prints "This is an int: 1337"

대신에:

print("Hello world!");
print_int(1337);

오버로드 된 함수가있을 때 컴파일러는 제공하는 매개 변수에서 호출 할 함수를 추론합니다. 기능 과부하를 작성할 때는주의를 기울여야합니다. 예를 들어 암시 적 유형 변환의 경우 :

void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}
void print(double num)
{
    std::cout << "This is a double: " << num << std::endl;
}

이제는 쓸 때 print 과부하가 불려지는 것을 즉시 알 수 없습니다 :

print(5);

그리고 컴파일러에 다음과 같은 단서를 제공해야 할 수도 있습니다.

print(static_cast<double>(5));
print(static_cast<int>(5));
print(5.0);

선택적 매개 변수를 허용하는 오버로드를 작성하는 경우 몇 가지주의를 기울여야합니다.

// WRONG CODE
void print(int num1, int num2 = 0)    //num2 defaults to 0 if not included
{ 
    std::cout << "These are ints: << num1 << " and " << num2 << std::endl;
}
void print(int num)
{
    std::cout << "This is an int: " << num << std::endl;
}

print(17) 와 같은 호출이 선택적인 두 번째 매개 변수로 인해 첫 번째 또는 두 번째 함수를위한 것인지 여부를 컴파일러가 알 수있는 방법이 없으므로 컴파일이 실패합니다.

함수 오버로딩의 리턴 타입

함수의 반환 유형에 따라 함수를 오버로드 할 수 없습니다. 예 :

// WRONG CODE
std::string getValue()
{
  return "hello";
}

int getValue()
{
  return 0;
}

int x = getValue();

반환 형식이 int 할당되어 있어도 호출 할 getValue 버전을 컴파일러에서 처리 할 수 ​​없으므로 컴파일 오류가 발생합니다.

멤버 함수 cv-qualifier 오버로딩

클래스 내의 함수는, 그 클래스에 대한 cv 수식 된 참조를 개입시켜 액세스 할 때 오버로드 할 수 있습니다. 이것은 const 에 대한 오버로드에 가장 일반적으로 사용되지만 volatileconst volatile 에도 오버로드하는 데 사용할 수 있습니다. 이것은 모든 비 정적 멤버 함수가 this cv-qualifier가 적용된 숨겨진 매개 변수로 사용하기 때문입니다. 이것은 const 에 대한 오버로드에 가장 일반적으로 사용되지만 volatileconst volatile 에도 사용할 수 있습니다.

이것은 멤버 함수가 호출 된 인스턴스와 최소한 cv-qualified 인 경우에만 호출 될 수 있기 때문에 필요합니다. 비 있지만 const 인스턴스가 모두 호출 할 수 있습니다 const 및 비 const 멤버를하는 const 인스턴스는 호출 할 수 있습니다 const 회원. 이것은 호출하는 인스턴스의 cv-qualifier에 따라 함수가 다른 동작을 할 수있게 해주 며 프로그래머가 그 한정자를 가진 버전을 제공하지 않음으로써 원하지 않는 cv-qualifier에 대한 함수를 허용하지 않게합니다.

기본적인 print 방법을 가진 클래스는 다음과 같이 const 오버로드 될 수 있습니다.

#include <iostream>

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        void print()
        {
            std::cout << "int: " << i << std::endl;
        }

        void print() const
        {
            std::cout << "const int: " << i << std::endl;
        }

    protected:
        int i;
};

int main()
{
    Integer i{5};
    const Integer &ic = i;
    
    i.print(); // prints "int: 5"
    ic.print(); // prints "const int: 5"
}

이것은 const 정확성의 중요한 교리입니다. 멤버 함수를 const 로 표시하면 const 인스턴스에서 호출 할 수 있으며, 함수를 수정하지 않아도 함수가 const 포인터 / 참조로 사용할 수 있습니다. 이를 통해 코드는 수정되지 않은 매개 변수를 const 로 수정하고 cv 한정자없이 수정 된 매개 변수를 취함으로써 상태를 수정하는지 여부를 지정할 수 있으므로 코드가보다 안전하고 읽기 쉽습니다.

class ConstCorrect 
{
  public:
    void good_func() const 
    {
        std::cout << "I care not whether the instance is const." << std::endl;
    }

    void bad_func() 
    {
        std::cout << "I can only be called on non-const, non-volatile instances." << std::endl;
    }
};

void i_change_no_state(const ConstCorrect& cc) 
{
    std::cout << "I can take either a const or a non-const ConstCorrect." << std::endl;
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Error.  Can only be called from non-const instance.
}

void const_incorrect_func(ConstCorrect& cc) 
{
    cc.good_func(); // Good.  Can be called from const or non-const instance.
    cc.bad_func();  // Good.  Can only be called from non-const instance.
}

이것의 일반적인 사용법은 접근자를 const 로 선언하고 mutator를 비 const 로 선언하는 것입니다.


const 멤버 함수 내에서 클래스 멤버를 수정할 수 없습니다. std::mutex 를 잠그는 것과 같이 정말로 수정해야하는 멤버가 있다면, mutable 로 선언 할 수 있습니다 :

class Integer
{
    public:
        Integer(int i_): i{i_}{}

        int get() const
        {
            std::lock_guard<std::mutex> lock{mut};
            return i;
        }

        void set(int i_)
        {
            std::lock_guard<std::mutex> lock{mut};
            i = i_;
        }

    protected:
        int i;
        mutable std::mutex mut;
};


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow