수색…
소개
과부하 해결 에 관한 별도의 주제도 참조하십시오.
비고
모호성은 한 유형을 둘 이상의 유형으로 내재적으로 변환 할 수 있고 해당 유형에 대해 일치하는 기능이없는 경우 발생할 수 있습니다.
예 :
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
에 대한 오버로드에 가장 일반적으로 사용되지만 volatile
및 const volatile
에도 오버로드하는 데 사용할 수 있습니다. 이것은 모든 비 정적 멤버 함수가 this
cv-qualifier가 적용된 숨겨진 매개 변수로 사용하기 때문입니다. 이것은 const
에 대한 오버로드에 가장 일반적으로 사용되지만 volatile
및 const 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;
};