표준 변환

C++ 언어에서는 기본 형식 간의 변환을 정의합니다. 또한 포인터, 참조 및 멤버 포인터 파생 형식에 대한 변환도 정의합니다. 이러한 변환을 표준 변환이라고 합니다.

이 단원에서는 다음과 같은 표준 변환에 대해 설명합니다.

  • 정수 계열 확장

  • 정수 계열 변환

  • 부동 변환

  • 부동 및 정수 계열 변환

  • 산술 변환

  • 포인터 변환

  • 참조 변환

  • 멤버 포인터 변환

    참고 항목

    사용자 정의 형식은 고유한 변환을 지정할 수 없습니다. 사용자 정의 형식의 변환은 생성자 및 변환에서 다룹니다.

다음 코드에서는 변환을 발생시킵니다(이 예제의 경우 정수 계열 확장).

long  long_num1, long_num2;
int   int_num;

// int_num promoted to type long prior to assignment.
long_num1 = int_num;

// int_num promoted to type long prior to multiplication.
long_num2 = int_num * long_num2;

참조 형식을 생성하는 경우에만 변환의 결과가 l-value입니다. 예를 들어 참조로 선언된 operator int&() 사용자 정의 변환은 참조를 반환하고 l-value입니다. 그러나 선언된 변환은 operator int() 개체를 반환하며 l-value가 아닙니다.

정수 계열 확장

정수 계열 형식의 개체를 다른 더 넓은 정수 계열 형식, 즉 더 큰 값 집합을 나타낼 수 있는 형식으로 변환할 수 있습니다. 이 확대 변환 유형을 정수 승격이라고합니다. 정수 계열 승격을 사용하면 다른 정수 계열 형식을 사용할 수 있는 모든 식에서 다음 형식을 사용할 수 있습니다.

  • 개체, 리터럴 및 형식 char 의 상수 및 short int

  • 열거형 형식

  • int 비트 필드

  • 열거자

C++ 승격은 승격 후 값이 승격 전 값과 같도록 보장되므로 "값 유지"입니다. 값 유지 승격에서는 원래 형식의 전체 범위를 나타낼 수 있는 경우 int 더 짧은 정수 계열 형식(예: 비트 필드 또는 형식 char개체)의 개체가 형식 int 으로 승격됩니다. 전체 값 범위를 나타낼 수 없으면 int 개체가 형식 unsigned int으로 승격됩니다. 이 전략은 표준 C에서 사용하는 전략과 동일하지만 값 유지 변환은 개체의 "서명성"을 유지하지 않습니다.

값을 보존하는 확장과 부호 유부를 보존하는 확장은 보통 동일한 결과를 생성합니다. 그러나 승격된 개체가 다음과 같이 표시되면 다른 결과를 생성할 수 있습니다.

  • , ,, <=%>/=<%=또는 피/연산자>=

    이 연산자는 부호를 사용하여 결과를 확인합니다. 값 보존 및 부호 유지 승격은 이러한 피연산자에 적용될 때 다른 결과를 생성합니다.

  • 의 왼쪽 피연산자 >>>>=

    이러한 연산자는 시프트 작업에서 서명된 수량과 서명되지 않은 수량을 다르게 처리합니다. 부호 있는 수량의 경우 오른쪽 시프트 작업은 부호 있는 비트 위치를 비운 비트 위치로 전파하고, 비어 있는 비트 위치는 부호 없는 수량으로 채워지지 않습니다.

  • 인수 일치를 위해 피연산자 형식의 부호에 따라 달라지는 오버로드된 함수 또는 오버로드된 연산자의 피연산자에 대한 인수입니다. 오버로드된 연산자를 정의하는 방법에 대한 자세한 내용은 오버로드된 연산자를 참조 하세요.

정수 계열 변환

정수 변환은 정수 계열 형식 간의 변환입니다. 정수 계열 형식은 char, short (또는 short int) int, longlong long. 이러한 형식은 정규화 signed 될 수 있으며 unsigned ,에 대한 unsigned int약식으로 unsigned사용할 수 있습니다.

서명되지 않은 상태로 서명됨

부호가 있는 정수 계열 형식의 개체를 부호가 없는 해당 형식으로 변환할 수 있습니다. 이러한 변환이 발생하면 실제 비트 패턴이 변경되지 않습니다. 그러나 데이터 해석이 변경되었습니다. 다음과 같은 코드를 생각해 볼 수 있습니다.

#include <iostream>

using namespace std;
int main()
{
    short  i = -3;
    unsigned short u;

    cout << (u = i) << "\n";
}
// Output: 65533

앞의 예제에서 , isigned short정의되고 음수로 초기화됩니다. 이 식 (u = i)i 은 할당 전에 . unsigned short 로 변환됩니다 u.

서명되지 않음

부호 없는 정수 계열 형식의 개체를 부호 있는 해당 형식으로 변환할 수 있습니다. 그러나 부호 없는 값이 부호 있는 형식의 표시 가능한 범위를 벗어나면 다음 예제와 같이 결과에 올바른 값이 없습니다.

#include <iostream>

using namespace std;
int main()
{
short  i;
unsigned short u = 65533;

cout << (i = u) << "\n";
}
//Output: -3

앞의 예제 uunsigned short 에서는 식을 (i = u)평가하기 위해 서명된 수량으로 변환해야 하는 정수 개체입니다. 해당 값을 제대로 나타낼 signed short수 없으므로 표시된 대로 데이터가 잘못 해석됩니다.

부동 소수점 변환

부동 형식의 개체를 보다 정확한 부동 형식으로 안전하게 변환할 수 있습니다. 즉, 변환으로 인해 유의성이 손실되지 않습니다. 예를 들어 대/중 doublelong double 변환 floatdouble 은 안전하며 값은 변경되지 않습니다.

부동 형식의 개체가 해당 형식으로 나타낼 수 있는 범위에 있는 경우 덜 정확한 형식으로 변환할 수도 있습니다. (참조) 부동 형식의 범위에 대한 부동 제한 입니다.) 원래 값을 정확하게 나타낼 수 없는 경우 다음으로 더 높거나 다음으로 낮은 표현 가능한 값으로 변환할 수 있습니다. 이러한 값이 없으면 결과가 정의되지 않습니다. 다음 예제를 참조하세요.

cout << (float)1E300 << endl;

형식 float 으로 나타낼 수 있는 최대값은 1E300보다 훨씬 작은 3.402823466E38입니다. 따라서 숫자는 무한대로 변환되고 결과는 "inf"입니다.

정수 계열 및 부동 소수점 형식 간의 변환

특정 식은 부동 형식의 개체가 정수 계열 형식으로 변환되도록 하거나 그 반대로 변환되도록 할 수 있습니다. 정수 계열 형식의 개체가 부동 형식으로 변환되고 원래 값을 정확하게 나타낼 수 없는 경우 결과는 다음으로 높거나 다음으로 낮은 표현 가능한 값입니다.

부동 형식의 개체가 정수 형식으로 변환되면 소수 부분이 잘리거나 0으로 반올림됩니다. 1.3과 같은 숫자는 1로 변환되고 -1.3은 -1로 변환됩니다. 잘린 값이 가장 높은 표현 가능한 값보다 높거나 가장 낮은 표현 가능한 값보다 낮으면 결과는 정의되지 않습니다.

산술 변환

많은 이진 연산자(이진 연산자를 사용하여 식에서 설명됨)는 피연산자를 변환하고 결과를 동일한 방식으로 생성합니다. 이러한 연산자가 유발하는 변환을 일반적인 산술 변환이라고 합니다. 다음 표와 같이 네이티브 형식이 다른 피연산자의 산술 변환이 수행됩니다. typedef 형식은 해당 기본 네이티브 형식에 따라 동작합니다.

형식 변환 조건

조건 충족 전환
피연산자 중 하나가 형식 long double입니다. 다른 피연산자는 형식 long double으로 변환됩니다.
이전 조건이 충족되지 않고 피연산자 중 하나가 형식 double입니다. 다른 피연산자는 형식 double으로 변환됩니다.
이전 조건이 충족되지 않고 피연산자 중 하나가 형식 float입니다. 다른 피연산자는 형식 float으로 변환됩니다.
이전 조건이 충족되지 않았습니다(부동 형식인 피연산자가 없음). 피연산자는 다음과 같이 정수 승격을 가져옵니다.

- 피연산자 중 하나가 형식 unsigned long인 경우 다른 피연산자는 형식 unsigned long으로 변환됩니다.
- 이전 조건이 충족되지 않고 피연산자 중 하나가 형식 long 이고 다른 형식 unsigned int인 경우 두 피연산자는 모두 형식 unsigned long으로 변환됩니다.
- 위의 두 조건이 충족되지 않고 피연산자 중 하나가 형식 long인 경우 다른 피연산자는 형식 long으로 변환됩니다.
- 위의 세 조건이 충족되지 않고 피연산자 중 하나가 형식 unsigned int인 경우 다른 피연산자는 형식 unsigned int으로 변환됩니다.
- 위의 조건이 충족되지 않으면 두 피연산자는 모두 형식 int으로 변환됩니다.

다음 코드에서는 표에 설명된 변환 규칙을 보여 줍니다.

double dVal;
float fVal;
int iVal;
unsigned long ulVal;

int main() {
   // iVal converted to unsigned long
   // result of multiplication converted to double
   dVal = iVal * ulVal;

   // ulVal converted to float
   // result of addition converted to double
   dVal = ulVal + fVal;
}

위의 예제에서 첫 번째 문은 iValulVal이라는 두 정수 계열 형식을 곱한 것입니다. 충족되는 조건은 피연산자 모두 부동 형식이 아니고 하나의 피연산자는 형식 unsigned int입니다. 따라서 다른 피연산자는 iVal형식 unsigned int으로 변환됩니다. 그런 다음, 결과가 .에 할당됩니다 dVal. 여기서 충족되는 조건은 하나의 피연산자 형식 double이므로 unsigned int 곱하기 결과가 형식 double으로 변환됩니다.

앞의 예제의 두 번째 문은 정 float 수 계열 형식과 정수 계열 형식 fVal 을 더한 것을 보여 하며,ulVal ulVal 변수가 형식 float (테이블의 세 번째 조건)으로 변환됩니다. 추가의 결과는 형식 double (테이블의 두 번째 조건)으로 변환되고 에 할당됩니다 dVal.

포인터 변환

초기화, 할당, 비교 및 기타 식 실행 중에 포인터가 변환될 수 있습니다.

클래스 포인터

클래스에 대한 포인터가 기본 클래스에 대한 포인터로 변환될 수 있는 두 가지 경우가 있습니다.

첫 번째 경우는 지정된 기본 클래스에 액세스할 수 있고 변환이 명확한 경우입니다. 모호한 기본 클래스 참조에 대한 자세한 내용은 여러 기본 클래스를 참조 하세요.

기본 클래스에 액세스할 수 있는지 여부는 파생에서 사용되는 상속의 종류에 따라 달라집니다. 다음 그림에 설명된 상속을 고려합니다.

Diagram showing an inheritance graph and base class accessibility.

이 다이어그램은 기본 클래스 A를 보여 줍니다. 클래스 B는 개인 보호된 공용을 통해 A에서 상속됩니다. C 클래스는 공용 B를 통해 B에서 상속됩니다.

기본 클래스 접근성을 보여 주는 상속 그래프

다음 표에서는 그림에 나와 있는 상황에 대한 기본 클래스 액세스 가능성을 보여 줍니다.

함수 형식 파생 상품 B*에서 A*로의 변환이

B*A* 법적?
외부(클래스 범위가 아닌) 함수 프라이빗 아니요
Protected 아니요
공용
B 멤버 함수(B 범위에 있음) 프라이빗
Protected
공용
C 멤버 함수(C 범위에 있음) 프라이빗 아니요
Protected
공용

클래스에 대한 포인터가 기본 클래스에 대한 포인터로 변환될 수 있는 두 번째 경우는 명시적 형식 변환을 사용하는 경우입니다. 명시적 형식 변환에 대한 자세한 내용은 명시적 형식 변환 연산자를 참조 하세요.

이러한 변환의 결과는 하위 개체대한 포인터로, 기본 클래스에서 완전히 설명하는 개체 부분입니다.

다음 코드에서는 두 클래스 AB를 정의합니다. BA에서 파생됩니다. 상속에 대한 자세한 내용은파생 클래스입니다.) 그런 다음 개체를 bObject가리키는 두 개의 포인터(pApB)와 형식B의 개체를 정의합니다.

// C2039 expected
class A
{
public:
    int AComponent;
    int AMemberFunc();
};

class B : public A
{
public:
    int BComponent;
    int BMemberFunc();
};
int main()
{
   B bObject;
   A *pA = &bObject;
   B *pB = &bObject;

   pA->AMemberFunc();   // OK in class A
   pB->AMemberFunc();   // OK: inherited from class A
   pA->BMemberFunc();   // Error: not in class A
}

포인터 pA 는 "형식A *의 개체에 대한 포인터"를 의미하는 것으로 해석될 수 있는 형식A입니다. (예: BComponent 및)의 bObject 멤버는 형식 B 에 고유하므로 을 통해 pABMemberFunc액세스할 수 없습니다. pA 포인터는 A 클래스에서 정의된 개체의 특성(멤버 함수 및 데이터)에만 액세스할 수 있습니다.

함수 포인터

형식이 해당 포인터를 보유할 수 있을 만큼 큰 경우 함수에 대한 포인터를 형식 void *void * 으로 변환할 수 있습니다.

void 포인터

형식 void 에 대한 포인터는 다른 형식에 대한 포인터로 변환할 수 있지만 C와 달리 명시적 형식 캐스트를 사용하는 경우에만 가능합니다. 모든 형식에 대한 포인터를 암시적으로 형식 void에 대한 포인터로 변환할 수 있습니다. 형식의 불완전한 개체에 대한 포인터는 (암시적으로) 및 뒤로(명시적으로) 포인터 void 로 변환할 수 있습니다. 이러한 변환 결과는 원래 포인터 값과 같습니다. 개체가 선언된 경우 불완전한 것으로 간주되지만 크기 또는 기본 클래스를 결정하는 데 사용할 수 있는 정보가 부족합니다.

형식void *의 포인터로 암시적으로 변환되지 않거나 constvolatile 암시적으로 변환할 수 있는 개체에 대한 포인터입니다.

const 및 volatile 포인터

C++는 형식 또는 형식에서 const 형식이 아닌 형식으로의 표준 변환을 제공하지 않습니다volatileconst.volatile 하지만 모든 종류의 변환은 명시적 형식 캐스트를 사용하여 지정할 수 있습니다(안전하지 않은 변환 포함).

참고 항목

정적 멤버에 대한 포인터를 제외한 멤버에 대한 C++ 포인터는 일반 포인터와 다르며 표준 변환이 동일하지 않습니다. 정적 멤버에 대한 포인터는 일반 포인터이며 일반 포인터와 동일한 변환이 적용됩니다.

null 포인터 변환

0으로 계산되는 정수 상수 식 또는 포인터 형식으로 캐스팅된 식은 null 포인터라는 포인터로 변환됩니다. 이 포인터는 항상 포인터와 같지 않은 개체 또는 함수를 비교합니다. 예외는 동일한 오프셋을 가질 수 있고 여전히 다른 개체를 가리킬 수 있는 기반 개체에 대한 포인터입니다.

C++11 에서는 C 스타일 null 포인터에 nullptr 형식을 선호해야 합니다.

포인터 식 변환

배열 형식의 식을 동일한 형식의 포인터로 변환할 수 있습니다. 변환 결과는 첫 번째 배열 요소의 포인터입니다. 다음 예제에서는 이러한 변환에 대해 설명합니다.

char szPath[_MAX_PATH]; // Array of type char.
char *pszPath = szPath; // Equals &szPath[0].

특정 형식을 반환하는 함수를 도출하는 식은 해당 형식을 반환하는 함수의 포인터로 변환됩니다. 단, 다음의 경우는 제외됩니다.

  • 식은 address-of 연산자(&)에 대한 피연산자로 사용됩니다.

  • 해당 식이 함수 호출 연산자의 피연산자로 사용됩니다.

참조 변환

다음과 같은 경우 클래스에 대한 참조를 기본 클래스에 대한 참조로 변환할 수 있습니다.

  • 지정된 기본 클래스에 액세스할 수 있습니다.

  • 해당 변환은 명확합니다. (모호한 기본 클래스 참조에 대한 자세한 내용은 다음을 참조하세요 .여러 기본 클래스.)

변환의 결과는 기본 클래스를 나타내는 하위 개체에 대한 포인터입니다.

멤버 포인터

할당, 초기화, 비교 및 기타 식 실행 중에 클래스 멤버에 대한 포인터가 변환될 수 있습니다. 이 단원에서는 다음과 같은 멤버 포인터 변환에 대해 설명합니다.

기본 클래스 멤버 포인터

기본 클래스의 멤버에 대한 포인터는 다음 조건이 충족될 때 파생되는 클래스의 멤버에 대한 포인터로 변환할 수 있습니다.

  • 포인터에서 파생 클래스 및 기본 클래스 포인터로의 역 변환에 액세스할 수 있습니다.

  • 파생 클래스는 기본 클래스에서 사실상 상속되지 않습니다.

왼쪽 피연산자가 멤버에 대한 포인터인 경우 오른쪽 피연산자가 멤버 포인터 형식이거나 0으로 계산되는 상수 식이어야 합니다. 이 대입은 다음과 같은 경우에만 유효합니다.

  • 오른쪽 피연산자가 왼쪽 피연산자와 같은 클래스의 멤버에 대한 포인터입니다.

  • 왼쪽 피연산자가 오른쪽 피연산자의 클래스로부터 공개적으로 명확하게 파생된 클래스의 멤버에 대한 포인터입니다.

멤버 변환에 대한 null 포인터

0으로 계산되는 정수 상수 식은 null 포인터로 변환됩니다. 이 포인터는 항상 포인터와 같지 않은 개체 또는 함수를 비교합니다. 예외는 동일한 오프셋을 가질 수 있고 여전히 다른 개체를 가리킬 수 있는 기반 개체에 대한 포인터입니다.

다음 코드에서는 i 클래스의 A 멤버에 대한 포인터 정의에 대해 설명합니다. pai 포인터는 0으로 초기화되어 null 포인터가 됩니다.

class A
{
public:
int i;
};

int A::*pai = 0;

int main()
{
}

참고 항목

C++ 언어 참조