함수 오버로드
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
함수 오버로딩은 동일한 이름을 가진 둘 이상의 함수를 정의하는 프로그래밍 기능이다. 함수 오버로딩을 지원하는 언어로는 에이다, 에이펙스, C++, C#, 클로저, 스위프트, 포트란, 코틀린, 자바, 줄리아 등이 있다. C++에서는 매개변수의 타입, 개수, const/volatile 한정자의 차이에 따라 함수를 오버로딩할 수 있다. 함수 오버로딩은 코드의 가독성과 유지보수성을 높일 수 있지만, 과도하게 사용하면 오히려 코드를 이해하기 어렵게 만들 수 있다.
더 읽어볼만한 페이지
- 메소드 (컴퓨터 프로그래밍) - 소멸자 (컴퓨터 프로그래밍)
소멸자는 객체가 메모리에서 제거되기 직전에 호출되는 멤버 함수로, 객체 자원 해제 및 정리 작업을 수행하며, C++ 등 여러 언어에서 구현되고 메모리 누수 방지에 기여한다. - 메소드 (컴퓨터 프로그래밍) - 동적 디스패치
동적 디스패치는 프로그램 실행 시 호출할 메서드를 결정하는 메커니즘으로, 단일 또는 다중 객체 기준으로 선택하며, 유연성과 확장성을 높이지만 성능 오버헤드를 발생시킬 수 있다. - 프로그래밍 구성체 - 형 변환
형 변환은 프로그래밍에서 변수의 데이터 타입을 변경하는 것으로, 암시적 형 변환과 명시적 형 변환으로 나뉘며, 객체 지향 프로그래밍에서는 업캐스팅과 다운캐스팅이 발생하고, 각 언어는 고유한 규칙과 방법을 제공하며 잘못된 형 변환은 오류를 유발할 수 있다. - 프로그래밍 구성체 - 연산자 오버로딩
연산자 오버로딩은 프로그래밍 언어에서 기존 연산자를 사용자 정의 자료형에 대해 재정의하여 내장 자료형처럼 다루도록 하는 기능으로, 코드 가독성과 표현력을 높이지만 남용 시 코드 의미를 모호하게 만들 수 있다.
함수 오버로드 | |
---|---|
다중 정의 | |
다른 이름 | 함수 오버로딩, 연산자 오버로딩, 메서드 오버로딩 |
영어 이름 | function overloading, operator overloading, method overloading |
설명 | 다중 정의(多重定義, 영어: overloading, 오버로딩) 또는 오버로드(overload)는 프로그래밍에서, 같은 이름의 함수 또는 연산자를 여러 정의를 가질 수 있게 하는 것을 의미한다. |
함수 오버로딩 | |
설명 | 함수 오버로딩(function overloading)은 여러 개의 함수가 같은 이름을 가지지만, 매개변수의 종류와 개수가 다르게 정의되는 것을 의미한다. 컴파일러는 함수 호출 시 전달되는 인수의 타입과 개수를 비교하여 어떤 함수를 호출할지 결정한다. 함수 오버로딩은 코드의 가독성을 높이고 유지보수를 용이하게 한다. |
연산자 오버로딩 | |
설명 | 연산자 오버로딩(operator overloading)은 기존에 정의된 연산자의 동작 방식을 변경하거나 확장하는 것을 의미한다. 사용자는 연산자를 클래스 객체에 대해 사용할 때, 연산자가 수행할 작업을 정의할 수 있다. 연산자 오버로딩은 코드의 가독성을 높이고, 사용자 정의 타입에 대한 직관적인 연산을 가능하게 한다. |
C++에서의 오버로딩 예시 | |
함수 오버로딩 예시 | int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } 위 예시에서 add 함수는 int형과 double형 인수를 모두 처리할 수 있도록 오버로딩되었다. |
연산자 오버로딩 예시 | class Complex { ... Complex operator+(const Complex& other) { ... } ... }; 위 예시에서 + 연산자는 Complex 클래스 객체에 대해 덧셈 연산을 수행하도록 오버로딩되었다. |
주의사항 | |
모호성 | 오버로딩된 함수 또는 연산자를 호출할 때, 컴파일러가 어떤 정의를 사용해야 할지 결정할 수 없는 경우 모호성 오류가 발생할 수 있다. 모호성 오류를 피하려면, 오버로딩된 함수 또는 연산자의 매개변수 타입을 명확하게 구분해야 한다. |
남용 | 오버로딩을 남용하면 코드의 가독성이 떨어지고 유지보수가 어려워질 수 있다. 오버로딩은 코드의 의미를 명확하게 전달할 수 있는 경우에만 사용하는 것이 좋다. |
지원하는 언어 | |
지원 언어 | C++ C# Java Kotlin Scala Swift Python PHP Ruby Perl |
2. 지원 언어
함수 오버로딩을 지원하는 대표적인 언어로는 C++C#, 코틀린[2], 자바, 스칼라, 타입스크립트 등이 있다.
C 언어는 함수 오버로딩을 지원하지 않는다. C에서는 함수의 인수 유형이나 수에 관계없이 알고리즘이 동일하더라도, 각기 다른 이름을 사용해야 한다. 반면, C++에서는 함수의 시그니처가 다르면 동일한 이름을 사용할 수 있어, 호출 시 인수에 관계없이 일관된 기술이 가능하다.
함수 오버로딩을 지원하는 다른 언어들은 다음을 포함한다.
타입이 지정된 프로그래밍 언어에서는 함수나 연산자에 주어진 인수 (연산자라면 오퍼랜드)의 타입 정보가 사용된다. 함수의 이름과 타입 정보를 조합한 것을 시그니처라고 하며, 시그니처가 유일하게 결정되면 함수명이나 메소드명, 연산자 기호가 중복되어도 호출 대상을 유일하게 결정할 수 있다.
기본 인수를 지원하지 않는 언어 (자바 또는 버전 4.0 이전의 C# 등)에서는, 다중 정의를 통해 기본 인수와 유사한 기능을 구현할 수 있다.
2. 1. C++
C++은 함수 오버로딩을 지원하는 대표적인 언어이다. C++에서는 매개변수의 타입, 개수, const/volatile 한정자의 차이에 따라 함수를 오버로딩할 수 있다.C++의 함수 오버로딩 예시는 다음과 같다.
```c++
#include
#include
float vector_length(float x, float y) { return std::sqrt(x * x + y * y); }
double vector_length(double x, double y) { return std::sqrt(x * x + y * y); }
float vector_length(float x, float y, float z) { return std::sqrt(x * x + y * y + z * z); }
double vector_length(double x, double y, float z) { return std::sqrt(x * x + y * y + z * z); }
int main(void)
{
printf("%f\n", vector_length(1.0f, -1.0f)); // (float, float) 버전이 호출된다.
printf("%f\n", vector_length(1.0, 2.0)); // (double, double) 버전이 호출된다.
printf("%f\n", vector_length(1.0f, -1.0f, 1.0f)); // (float, float, float) 버전이 호출된다.
printf("%f\n", vector_length(1.0, 2.0, -1.0)); // (double, double, double) 버전이 호출된다.
}
```
위 예시에서 `vector_length` 함수는 매개변수의 타입과 개수에 따라 여러 버전으로 오버로딩되어 있다.
C++11 규격에서는 2차원 벡터의 길이를 구하는 표준 함수로, 오버로딩된 `std::hypot()` 함수가 제공된다[23]. C++17에서는 3차원 벡터 버전도 추가되었다.
C++에서는 기본적으로 "(1) 인수의 수", "(2) 수식어", "(3) 타입"이 다르면 함수에 같은 이름을 붙일 수 있다. 다음은 그 예시이다[24].
```c++
// (1-1): 인수의 수의 차이에 따른 다중 정의
int Function(void);
int Function( int value );
int Function( int value0, int value1 );
// (2): 인수의 수식어의 차이에 따른 다중 정의
int Function( int *value );
int Function( int const *value );
int Function( int *const *value );
int Function( int *const *const *value );
// (3): 인수의 타입의 차이에 따른 다중 정의
int Function( char value );
int Function( std::complex< double > const &value );
int Function( ... ); // ※1
template< class Type > int Function( Type const &value ); // ※2
struct Example
{
// (1-2): 인수의 타입의 차이에 따른 다중 정의(생성자 버전)
Example(void);
Example( int value );
// (4): 멤버 함수의 수식어의 차이에 따른 다중 정의
int Function(void);
int Function(void) const;
// (1-3): 인수의 타입의 차이에 따른 다중 정의(멤버 함수 버전)
int Function( int value );
// (5): 반환 값의 타입의 차이에 따른 다중 정의
operator bool (void) const;
operator int (void) const;
};
```
멤버 함수는 추가적으로 "(4) 수식어의 차이"와 변환 연산자를 사용했을 때 "(5) 반환 값의 타입의 차이"에 따른 다중 정의가 가능하다. Java(자바)나 C# 등 C++ 이외의 언어에서는 (1)과 (3)의 범위에 머무는 경우가 많다.
C++에서 특징적인 것은 ※1의 생략자와 ※2의 템플릿 함수를 다중 정의할 수 있다는 점이다. 생략자를 인수로 취하는 함수는 모든 인수를 받을 수 있다. 템플릿 함수는 명시적으로 타입을 쓴 함수보다 선택되는 우선 순위가 낮고, 생략자를 사용한 함수는 더욱 낮다.
2. 2. Java
자바는 C++와 마찬가지로 함수 오버로딩을 지원한다. Java에서는 매개변수의 타입과 개수에 따라 함수를 오버로딩할 수 있다.[2]3. 오버로딩 규칙
함수 오버로딩은 동일한 함수 이름에 대해 서로 다른 타입 시그니처를 가지는 여러 개의 함수 정의를 허용한다. 함수 시그니처에는 함수의 이름, 매개변수의 수, 타입, 순서 등이 포함된다.[8] 컴파일러는 함수 호출 시점에 주어진 인수의 타입과 개수에 가장 적합한 함수를 선택하여 호출한다.
함수 오버로딩의 규칙은 다음과 같다.
- 특정 모듈, 클래스 또는 네임스페이스 내에서 동일한 함수 이름이 둘 이상의 함수 정의에 사용된다.
- 함수는 서로 다른 타입 시그니처를 가져야 한다. 즉, 형식 매개변수의 수 또는 타입(C++의 경우) 또는 반환 타입(Ada의 경우)이 달라야 한다.[8]
함수 오버로딩은 정적으로 타입이 지정된 프로그래밍 언어에서 함수 호출 시 타입 검사를 시행하는 것과 관련이 있다. 오버로드된 함수는 동일한 이름으로 호출할 수 있는 서로 다른 함수 집합이다. 특정 호출의 경우 컴파일러는 사용할 오버로드된 함수를 결정하고 이를 컴파일 시간에 해결한다.
함수 오버로딩은 선택이 정적으로 수행되는 대신 다형성의 한 형태인 가상 함수처럼 런타임에 수행되는 것과는 다르다.
4. 생성자 오버로딩
객체 지향 프로그래밍에서 생성자는 객체를 초기화하는 특별한 메서드이다. 생성자도 함수 오버로딩을 통해 여러 개의 생성자를 정의할 수 있다. 이를 통해 객체 생성 시점에 다양한 초기화 방법을 제공할 수 있다.
많은 객체 지향 프로그래밍 언어에서 생성자의 이름은 클래스 이름에 의해 미리 결정되기 때문에 생성자는 하나만 있을 수 있는 것처럼 보인다. 그러나 여러 생성자가 필요할 때마다 오버로딩된 함수로 구현해야 한다. C++에서 기본 생성자는 매개변수를 받지 않으며, 객체 인스턴스 변수를 적절한 기본값으로 인스턴스화한다. 예를 들어, C++로 작성된 식당 계산서 객체에 대한 기본 생성자는 팁을 15%로 설정할 수 있다.[9]
C++ 코드 예시:
```cpp
Bill()
: tip(0.15), // percentage
total(0.0)
{ }
```
이 경우 생성된 Bill 객체의 값을 변경하려면 두 단계가 필요하다는 단점이 있다.
C++ 코드 예시:
```cpp
Bill cafe;
cafe.tip = 0.10;
cafe.total = 4.00;
```
그러나 생성자를 오버로딩하면 팁과 총액을 생성 시 매개변수로 전달할 수 있다. 다음은 두 개의 매개변수를 가진 오버로딩된 생성자의 예시이다.
C++ 코드 예시:
```cpp
Bill(double tip, double total)
: tip(tip),
total(total)
{ }
```
이제 새로운 Bill 객체를 생성하는 함수는 생성자에 두 개의 값을 전달하고 한 단계로 데이터 멤버를 설정할 수 있다.
C++ 코드 예시:
```cpp
Bill cafe(0.10, 4.00);
```
이렇게 생성자 오버로딩을 활용하면 프로그램 효율성을 높이고 코드 길이를 줄일 수 있다.
생성자 오버로딩의 또 다른 이유는 필수 데이터 멤버를 적용하기 위한 것이다. 이 경우 기본 생성자는 외부에서 접근할 수 없도록 private 또는 protected (또는 C++11 이후로는 삭제)로 선언된다.
5. 주의 사항
함수 오버로딩은 코드 가독성과 유지보수성을 높일 수 있지만, 과도하게 사용하면 오히려 코드를 이해하기 어렵게 만들 수 있다. 특히 묵시적 형식 변환과 함께 사용하면 어떤 함수가 호출될지 예측하기 어려워 유지보수에 어려움을 겪을 수 있다.[11]
메서드가 너무 많은 오버로드를 가지면 개발자가 코드를 읽는 것만으로 어떤 오버로드가 호출되는지 파악하기 어려울 수 있는데, 이는 오버로드된 매개변수 중 일부가 다른 가능한 매개변수의 상속된 유형인 경우 특히 그렇다. 통합 개발 환경(IDE)은 오버로드 확인을 수행하여 올바른 오버로드를 표시하거나 탐색할 수 있도록 돕는다.
타입 기반 오버로드는 코드 유지 관리에 문제를 일으킬 수 있는데, 코드 업데이트로 인해 컴파일러가 선택하는 메서드 오버로드가 의도치 않게 변경될 수 있기 때문이다.[11]
함수 오버로딩은 이름 가리기(범위 때문에) 및 묵시적 형식 변환과 함께 사용될 때 특히 복잡해진다. 함수를 선택할 때 사용되는 대표적인 문맥 정보로는, 타입이 지정된 프로그래밍 언어에서 함수나 연산자에 실제 인수(연산자라면 오퍼랜드)로 주어진 식이나 변수와 관련된 타입 정보가 사용된다.
이론적으로 함수의 이름은 단순한 기호이며 의미적 필연성이 있는 것은 아니지만, 함수 이름, 메서드, 특히 연산자의 용법에는 각 분야 및 프로그래밍 언어마다 관습이 형성되어 있는 경우가 있다. 따라서 유명한 함수나 메서드, 연산자에 대해 관습과 너무 동떨어진 의미를 부여하면 프로그램의 가독성이 현저하게 저하될 수 있으므로 주의해야 한다.
기본 인수(옵션 인수)를 지원하지 않는 언어 (자바 또는 버전 4.0 이전의 C# 등)에서는, 다중 정의에 의해 기본 인수와 유사한 기능을 실현할 수 있다.
함수, 메서드 및 연산자가 다중 정의된 경우, 해당 이름만으로는 구별할 수 없으므로, 다중 정의 후보 중 어떤 버전이 사용되는지 소스 코드 상에서 한눈에 알기 어려워 가독성이 떨어진다. 통합 개발 환경(IDE) 중에는 구문 분석을 통해 어떤 버전이 어디에서 사용되고 있는지 열거해 주는 것도 있지만, 그러한 도구를 사용할 수 없는 상황에서는 읽는 사람이 자세한 검색 지식을 갖고 있지 않으면 판별이 어려운 경우도 있다.
예를 들어, C++(C++)에서 어떤 수치형(예: 유리수형)을 위한 클래스를 정의한다고 가정하고, 정수형을 인수로 받는 abs 함수가 절대값을 반환함에도 불구하고 유리수형을 받는 abs 함수를 전혀 다른 의미로 정의하면 함수 템플릿 등에서 같은 처리를 공유할 수 없을 뿐만 아니라 혼란을 야기한다. 따라서 호환성이 없는 다중 정의는 피해야 한다.
5. 1. 이름 가리기
함수 오버로딩은 이름 가리기(범위 때문에)와 묵시적 형식 변환과 겹쳐 복잡한 문제를 일으킬 수 있다.[10]함수가 한 범위에서 선언되고, 같은 이름을 가진 다른 함수가 내부 범위에서 선언된다면, 내부 선언이 외부 선언을 가리거나(시그니처와 관계없이), 내부 선언과 외부 선언 모두 오버로드에 포함되며 시그니처가 일치하는 경우에만 내부 선언이 외부 선언을 가리는 두 가지 방식으로 동작할 수 있다. C++에서는 전자의 방식을 택한다. 즉, "C++에서는 범위 간의 오버로딩이 없다."[10]
따라서, 다른 범위에서 선언된 함수로 오버로드 세트를 구성하려면, `using` 키워드를 사용하여 외부 범위의 함수를 내부 범위로 명시적으로 가져와야 한다.
묵시적 형식 변환은 함수 오버로딩을 더욱 복잡하게 만드는데, 매개변수 형식이 오버로드된 함수 중 하나의 시그니처와 정확히 일치하지 않더라도, 형식 변환을 통해 일치할 수 있기 때문이다. 이 경우 어떤 형식 변환을 선택하느냐에 따라 어떤 함수가 호출될지가 결정된다.
이러한 문제들은 복합적으로 작용하여 혼란을 야기할 수 있다. 예를 들어, 내부 범위에서 선언된, 정확하지 않은 일치 항목(묵시적 형 변환을 통해 일치)이 외부 범위에서 선언된 정확한 일치 항목을 가릴 수 있다.[10]
6. 템플릿과 다중 정의 (C++)
C++과 같이 다중 정의와 템플릿을 모두 지원하는 언어에서는 이 두 기능을 결합하여 정적 다형성을 구현할 수 있다. 이는 컴파일 시간에 함수 호출을 결정하여 런타임에 함수 호출을 결정하는 동적 다형성과는 달리 성능 향상을 기대할 수 있다.[24]
C++에서 다중 정의는 기본적으로 "(1) 인수의 수", "(2) 수식어", "(3) 타입"이 다르면 함수에 같은 이름을 붙일 수 있도록 되어 있다. 멤버 함수는 추가로 "(4) 수식어의 차이" 및 변환 연산자를 사용했을 때 "(5) 반환 값의 타입 차이"에 따른 다중 정의도 가능하다.
```c++
// (1-1): 인수의 수의 차이에 따른 다중 정의
int Function(void);
int Function( int value );
int Function( int value0, int value1 );
// (2): 인수의 수식어의 차이에 따른 다중 정의
int Function( int *value );
int Function( int const *value );
int Function( int *const *value );
int Function( int *const *const *value );
// (3): 인수의 타입의 차이에 따른 다중 정의
int Function( char value );
int Function( std::complex< double > const &value );
int Function( ... ); // ※1
template< class Type > int Function( Type const &value ); // ※2
struct Example
{
// (1-2): 인수의 타입의 차이에 따른 다중 정의(생성자 버전)
Example(void);
Example( int value );
// (4): 멤버 함수의 수식어의 차이에 따른 다중 정의
int Function(void);
int Function(void) const;
// (1-3): 인수의 타입의 차이에 따른 다중 정의(멤버 함수 버전)
int Function( int value );
// (5): 반환 값의 타입의 차이에 따른 다중 정의
operator bool (void) const;
operator int (void) const;
};
```
C++에서는 생략자(※1)와 템플릿 함수(※2)를 다중 정의할 수 있다. 생략자를 인수로 취하는 함수는 모든 인수를 받을 수 있지만, 함수 내부에서 인수를 참조할 수 없다. 템플릿 함수는 명시적으로 타입을 쓴 함수보다 선택 우선 순위가 낮고, 생략자를 사용한 함수는 더욱 낮다. 이러한 특성을 이용하여 특별한 처리가 필요한 타입은 명시적으로 타입을 쓴 함수로, 그렇지 않은 경우는 템플릿 함수로 처리하는 방식으로 정적 다형성을 구현할 수 있다.
템플릿과 다중 정의를 함께 사용하면, 다중 정의로 오버라이드를 대체할 수 있다. 예를 들어, 다음 `Sign` 함수는 인자 `value`의 부호에 따라 -1, 1 또는 0을 반환한다.
```cpp
// 인자 value의 부호에 따라 -1, 1 또는 0을 반환하는 함수.
template
{
return Type() == value ? Type() : abs( value ) / value; // 나눗셈 연산자 및 abs 함수의 실체는 Sign의 인자에 따라 달라진다.
}
```
이 함수 템플릿은 `double` 형뿐만 아니라 `std::complex`와 같은 복소수 타입에도 적용할 수 있다. 이 경우, `Sign` 함수는 정규화된 복소수를 반환하며, 이는 부호 함수의 복소수 확장과 일치한다.
이처럼 템플릿과 다중 정의를 활용하면, 멤버 함수뿐만 아니라 전역 함수도 클래스 인터페이스의 일부로 간주할 수 있다. 또한, 외부 라이브러리의 클래스에 멤버 함수를 추가하는 대신 전역 함수를 추가하여 기능을 확장하는 유연성을 확보할 수 있다. 더 나아가, 다중 디스패치를 흉내 내어 그리기 대상 장치에 따라 다른 방식으로 사각형을 그리는 등의 처리를 자연스럽게 기술할 수 있다.
인수 의존 이름 검색을 이용하면 네임스페이스 내에서도 다형성을 실현할 수 있다.[24]
7. 다중 정의의 장점
함수 오버로드는 코드 재사용성을 높이고, 함수 호출 시 인수의 타입이나 개수에 따라 적절한 함수가 자동으로 선택되므로 코드 가독성을 높이는 데 기여한다.
타입이 지정된 프로그래밍 언어에서는 함수나 연산자에 실제 인수(연산자라면 오퍼랜드)로 주어진 식이나 변수와 관련된 타입 정보가 사용된다. 드물지만 반환값의 타입을 이용할 수 있는 프로그래밍 언어도 존재한다. 함수의 이름과 이러한 타입 정보를 조합한 것을 시그니처라고 부르는데, 프로그램 내에서 시그니처가 유일하게 결정되면 함수명이나 메소드명, 연산자 기호가 중복되어도 호출해야 할 대상을 유일하게 결정할 수 있다. 이러한 타입 지정에 의한 다중 정의는 암묵적인 형 변환[16] 또는 타입 강제[17]), 상속[18] 또는 포함[19], 제네릭[20], 또는 파라미터화된 타입[21]과 함께 프로그래밍 언어에서 다형성[22]을 실현하기 위한 하나의 수단이다.
이론적으로 함수의 이름이나 연산자 기호는 단순한 기호이며, 의미적 필연성이 있는 것은 아니다. 이를 반영하여 다중 정의를 허용하는 프로그래밍 언어에서는 다중 정의된 함수나 연산자, 메소드의 의미나 동작의 정의는 상당히 자유롭게 할 수 있다. 그렇지만 함수명이나 메소드, 특히 연산자의 용법에는 각 분야 및 프로그래밍 언어마다 관습이 형성되어 있는 경우가 있으며, 유명한 함수(예를 들어 수학 함수의 `sin`)나 메소드, 연산자에 대해 관습과 너무나 동떨어진 의미, 즉 동작의 정의를 부여하면 프로그램의 가독성이 현저하게 저하될 가능성이 있으므로 주의해야 한다.
기본 인수(옵션 인수)를 지원하지 않는 언어(자바 또는 버전 4.0 이전의 C# 등)에서는, 다중 정의에 의해 기본 인수와 유사한 기능을 실현할 수 있다.
8. 다중 정의의 단점
메소드(함수)가 너무 많은 오버로드로 설계되면, 개발자들이 코드를 읽는 것만으로는 어떤 오버로드가 호출되는지 파악하기 어려울 수 있다. 이는 오버로드된 매개변수 중 일부가 다른 가능한 매개변수의 상속된 유형(예: "object")인 경우 특히 그렇다. 통합 개발 환경(IDE)은 오버로드 확인을 수행하고 올바른 오버로드를 표시(또는 탐색)할 수 있지만, 이러한 도구를 사용할 수 없는 상황에서는 읽는 사람이 자세한 검색 지식을 갖고 있지 않으면 판별이 어려운 경우도 있다.[11]
유형 기반 오버로드는 코드 유지 관리에도 지장을 줄 수 있으며, 코드 업데이트로 인해 컴파일러가 선택하는 메서드 오버로드가 실수로 변경될 수 있다.[11]
함수를 선택할 때 사용되는 대표적인 문맥 정보로는, 타입이 지정된 프로그래밍 언어에서는 함수나 연산자에 실제 인수 (연산자라면 오퍼랜드)로 주어진 식이나 변수와 관련된 타입 정보가 사용된다 (드물지만 반환값의 타입을 이용할 수 있는 프로그래밍 언어도 존재한다). 함수의 이름과 이러한 타입 정보를 조합한 것을 시그니처라고 부르는데, 프로그램 내에서 시그니처가 유일하게 결정되면 함수명이나 메소드명, 연산자 기호가 중복되어도 호출해야 할 대상을 유일하게 결정할 수 있다. 이러한 타입 지정에 의한 다중 정의는, 암묵적인 형 변환[16] 또는 타입 강제[17]), 상속[18] 또는 포함[19], 제네릭[20], 또는 파라미터화된 타입[21]과 함께 프로그래밍 언어에서 다형성[22]을 실현하기 위한 하나의 수단이다.
이론적으로 함수의 이름이나 연산자 기호는 단순한 기호이며, 의미적 필연성이 있는 것은 아니므로, 이를 반영하여 다중 정의를 허용하는 프로그래밍 언어에서는 다중 정의된 함수나 연산자, 메소드의 의미나 동작의 정의는 상당히 자유롭게 할 수 있다 (연산자에 대해서는 구문 분석의 편의상, 우선순위 등이 제한되는 경우도 있다). 그렇지만 함수명이나 메소드, 특히 연산자의 용법에는 각 분야 및 프로그래밍 언어마다 관습이 형성되어 있는 경우가 있으며, 유명한 함수 (예를 들어 수학 함수의 sin
등)나 메소드, 연산자에 대해 관습과 너무나 동떨어진 의미, 즉 동작의 정의를 부여하면 프로그램의 가독성이 현저하게 저하될 가능성이 있으므로 주의해야 한다.
함수/메서드 및 연산자가 다중 정의된 경우, 해당 이름만으로는 구별할 수 없으므로, 다중 정의 후보 중 어떤 버전이 사용되는지 소스 코드 상에서 한눈에 알기 어렵다.
예를 들어, C++(C++)에서 어떤 수치형, 예를 들어 유리수형을 위한 클래스를 정의한다고 가정하고, 정수형을 인수로 받는 abs 함수가 절대값을 반환함에도 불구하고 유리수형을 받는 abs 함수를 전혀 다른 의미로 정의하면 함수 템플릿 등에서 같은 처리를 공유할 수 없을 뿐만 아니라 혼란을 야기한다. 호환성이 없는 다중 정의는 피해야 한다.
참조
[1]
웹사이트
Clojure - Learn Clojure - Functions
https://clojure.org/[...]
2023-06-13
[2]
웹사이트
Kotlin language specification
https://kotlinlang.o[...]
[3]
웹사이트
37.6. Function Overloading
https://www.postgres[...]
2021-08-29
[4]
웹사이트
Database PL/SQL User's Guide and Reference
https://docs.oracle.[...]
2021-08-29
[5]
웹사이트
Nim Manual
https://nim-lang.org[...]
[6]
웹사이트
Crystal Docs
https://crystal-lang[...]
[7]
웹사이트
Embarcadero Delphi
https://docwiki.emba[...]
[8]
서적
Programming Language Design Concepts
John Wiley & Sons, Inc.
2004-05-01
[9]
서적
Learn C# in One Day and Learn It Well
2017
[10]
웹사이트
Why doesn't overloading work for derived classes?
http://www.stroustru[...]
[11]
웹사이트
Systemic Overload
https://gbracha.blog[...]
Room 101
2009-09-03
[12]
문서
function overloading
[13]
문서
operator overloading
[14]
문서
method overloding
[15]
문서
method overriding
[16]
문서
implicit type conversion
[17]
문서
type coercion
[18]
문서
inheritance
[19]
문서
inclusion
[20]
문서
generic type
[21]
문서
parametric type
[22]
문서
polymorphism
[23]
웹사이트
std::hypot - cppreference.com
https://ja.cpprefere[...]
[24]
PDF
http://www.open-std.[...]
[25]
PDF
http://www.j3-fortra[...]
[26]
웹사이트
オーバーロード
http://www.php.net/m[...]
The PHP Group
2014-04-16
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com