C++의 전방 선언

Dhruvdeep Singh Saini 2023년10월12일
  1. C++의 전방 선언
  2. C++에서 함수의 전방 선언
  3. C++에서 클래스의 전방 선언
  4. C++ 컴파일러에 전방 선언이 필요한 이유
  5. C++에서 정방향 선언 사용의 장점
C++의 전방 선언

이 기사에서는 정방향 선언을 설명하고 코드 예제와 함께 C++의 컴파일러에 이러한 선언이 필요한 이유를 보여줍니다.

이것은 또한 정방향 선언 사용의 이점에 대해 논의하고, 선언과 정의의 차이점을 강조하고, C++ 파일의 순환 종속성 오류를 피하기 위해 정방향 선언을 사용하는 방법을 보여줍니다.

C++의 전방 선언

정방향 선언은 프로그램에서 사용하기 전에 함수의 구문, 즉 이름, 반환 유형, 인수 및 인수의 데이터 유형을 선언하는 것입니다.

함수를 정의하기 전에 컴파일러가 프로그램의 어딘가에 함수가 정의되어 있음을 알리는 전방 선언을 포함합니다. 별도의 파일에서 사용되는 함수의 전방 선언은 #include를 사용하여 구성되어 파일을 갖습니다.

C++에서 함수의 전방 선언

코드 스니펫 내에서 전방 선언이 어떻게 작동하는지 봅시다.

#include <iostream>
using namespace std;

// forward declaration of sub2
int sub2(int A, int B);

int main() {
  cout << "Difference: " << sub2(25, 10);
  return 0;
}

int sub2(int A, int B)  // Defining sub2 here
{
  return A - B;
}

출력:

Difference: 15

여기에 전달된 두 int 매개변수의 차이를 반환하는 sub2라는 함수가 있습니다. 우리는 메인 파트 앞에 sub2를 선언하고 나중에 프로그램에서 함수를 정의합니다.

설명에 들어가기 전에 C++에서 정의와 선언의 차이점을 아는 것이 필수적입니다.

  1. 선언: 선언은 함수의 이름, 인수 및 데이터 유형, 반환 유형, 즉 함수 프로토타입과 같은 간단한 선언 정보를 제공합니다.
  2. 정의: 정의는 기능 선언의 세부사항을 제공하고 태스크 기능이 수행할 코드 스니펫을 포함합니다.

이제 forward 선언으로 돌아가 봅시다. 위 프로그램에서 sub2의 전방 선언이 필요한 이유는 무엇입니까?

이번에는 정방향 선언을 사용하지 않고 동일한 코드로 설명하겠습니다.

#include <iostream>
using namespace std;

int main() {
  cout << "Difference: " << sub2(25, 10);
  return 0;
}

int sub2(int A, int B)  // Defining sub2 here
{
  return A - B;
}

출력:

 error: 'sub2' was not declared in this scope
    6 |     cout << "Difference: " << sub2(25, 10);
      |                               ^~~~

위의 프로그램은 문제가 없지만 sub2 함수가 선언되지 않았다는 오류가 계속 표시됩니다. 이는 sub2가 6행에서 호출되었지만 10행 후반부까지 정의되지 않았기 때문입니다.

C++는 하향식 구문 분석 언어이기 때문에 상위에서 구문 분석 트리를 구성하고 사용하기 전에 함수에 대해 미리 알아야 합니다. 함수가 호출되기 전에 정의할 필요는 없지만 선언해야 합니다.

이러한 오류를 방지하기 위해 메인 함수 앞에 함수(여기서 sub2)를 정의할 수도 있습니다. 그러나 서로를 호출하거나 외부에 포함된 파일을 호출하는 여러 함수가 있는 프로그램에서는 오류가 지속되므로 정방향 선언을 사용합니다.

C++에서 클래스의 전방 선언

또한 C++에서 클래스의 전방 선언이 필요합니다. 방법을 보여드리겠습니다.

#include <iostream>
using namespace std;

// Forward declaration of classes One and Two
class One;
class Two;

class One {
  int y;

 public:
  void num(int a)  // Getting input number
  {
    y = a;
  }
  friend int sub2(One, Two);
};
class Two {
  int x;

 public:
  void num(int a)  // Getting input number
  {
    x = a;
  }
  friend int sub2(One, Two);
};
int sub2(One a, Two b)  // Subtraction of two numbers from both classes
{
  int ans = a.y - b.x;
  return ans;
}

int main() {
  Two y;
  One x;

  x.num(25);
  y.num(10);

  cout << "Difference: " << sub2(x, y);
  return 0;
}

출력:

Difference: 15

위의 코드 조각에는 OneTwo 클래스가 포함되어 있으며 둘 다 값을 가져오는 num 함수와 두 숫자를 빼는 sub2 함수가 있습니다.

One 클래스에는 매개변수에 언급된 Two 클래스와 함께 sub2 친구 함수가 포함되어 있으므로 위 프로그램에서는 두 클래스의 전방 선언이 필요합니다.

위의 코드 조각에서 클래스의 전방 선언을 제거하면 오류 메시지가 나타납니다.

15 |    [Error] 'Two' has not been declared In function 'int sub2(One, Two)':

이 오류는 컴파일러가 프로그램에서 사용하기 전에 함수 및 클래스의 전방 선언이 필요함을 보여줍니다.

C++ 컴파일러에 전방 선언이 필요한 이유

컴파일러가 다음 3가지를 보장하는 데 도움이 되므로 전방 선언이 필요합니다.

  • 프로그램이 정확하고 토큰 철자 오류가 없습니다.
  • 선언된 함수의 인수가 정확합니다.
  • 선언된 함수는 프로그램에 존재하며 아래와 같이 정의됩니다.

함수를 전달 선언하지 않은 경우 컴파일러는 함수가 무엇인지에 대한 다양한 추측 정보가 포함된 추가 개체 파일을 생성합니다.

그리고 링커(여러 개체와 클래스를 단일 실행 개체 파일로 연결하는 프로그램)에는 연결 문제가 있습니다. 동일한 이름의 기존 함수가 있지만 데이터 유형이 다른 인수가 있을 수 있기 때문입니다.

예를 들어 int sub2(int a, int b) 함수가 있다고 가정합니다. 포워드 선언이 없으면 링커는 다른 기존 함수 int sub2(float a, float b)와 혼동될 수 있습니다.

컴파일러는 C++ 정방향 선언으로 깨끗한 파일에 대한 코드의 유효성을 검사합니다. 어떤 경우에는 C++가 그러한 프로그램을 컴파일하고 실행할 수 있다는 것을 기억하는 것이 가장 좋습니다.

그러나 예상 출력을 제공하지 않습니다. 이것이 컴파일러가 코드를 구현하거나 사용하기 전에 전방 선언을 요구하는 이유입니다.

C++에서 정방향 선언 사용의 장점

전방 선언은 컴파일러가 코드를 더 잘 검증하고 연결 문제를 피하는 데 도움이 됩니다. 그러나 다음과 같은 도움도 됩니다.

  1. 네임스페이스 오염 방지: 전방 선언은 코드 조각이 잘못 배치되지 않도록 하고 네임스페이스를 오염시키는 것을 방지하는 데 도움이 됩니다.
  2. 컴파일 시간 개선: 헤더 파일을 포함하여 C++ 프로그램에 함수 선언을 추가할 수 있으며 컴파일러는 파일에 제공된 모든 토큰을 구문 분석하므로 시간이 오래 걸릴 수 있습니다. 그러나 이 긴 처리를 피하고 전체 cpp 파일 대신 사용하려는 특정 클래스에 대해 전방 선언을 사용할 수 있습니다.

이것은 더 작은 코드에는 영향을 미치지 않을 수 있지만 컴파일 시간을 최소화하여 시간 복잡성을 줄일 수 있으므로 더 중요한 프로젝트에서 유용합니다. 따라서 전체 C++ 파일을 포함하는 대신 .h 확장자를 가진 특정 클래스를 사용할 수 있습니다.

  1. 이름 충돌 방지: 전달 선언은 일치하는 함수 또는 클래스 이름을 가진 다른 프로젝트가 있는 경우 프로그램에서 토큰 또는 전처리기 이름의 충돌이 없는지 확인하는 데 도움이 됩니다.
  2. 순환 종속성 해제: 클래스의 정방향 선언은 파일에 필요한 특정 부분을 선언하고 헤더를 파일에서 제외함으로써 순환 참조를 해결할 수 있습니다.

C++에서 순방향 선언을 사용하여 순환 종속성 방지

서로 관련되거나 서로의 기능을 사용하는 두 클래스는 순환 관계를 만듭니다. 이를 순환 또는 순환 종속성이라고 합니다.

프로그램 내에서 둘 다 다른 클래스를 사용해야 하는 두 개의 클래스가 있다고 가정합니다. 이 경우 하나의 헤더 파일을 추가하지만 다른 순환 종속 클래스에 대한 헤더 파일을 추가로 포함하려고 시도하여 각 헤더가 다른 헤더를 가지려고 하는 주기를 만듭니다.

순환 종속성을 피하는 방법을 살펴보겠습니다.

#include <iostream>
#include <vector>

#include "Two.h"  // Defining Two as it is used in One

class One {
  std::vector<Two> two;
};

int main() { return 0; }

우리 프로그램에는 One 클래스에서 사용되는 #include를 사용하는 Two.h라는 이름의 또 다른 파일이 포함되어 있습니다. 위에서 설명한 것처럼 class.h 파일을 포함하고 다른 전체 프로그램은 포함하지 않으면 컴파일 시간이 크게 줄어듭니다.

이제 Two.h의 내용을 살펴보십시오.

#include "One.h"  // Defining One as it is used in Two

class Two {
  One* a;  // Two uses a pointer of One
};

‘Two.h’에는 ‘One’ 클래스의 포인터를 사용하는 Two 클래스가 포함되어 있습니다. 그러나 두 파일 모두 다른 파일을 포함하는 헤더를 포함하므로 두 파일이 계속 서로를 호출하는 순환 종속성에 갇히게 됩니다. 이것은 Two.h에 헤더를 추가하는 대신 다음과 같이 정방향 선언을 사용하여 피할 수 있습니다.

#include <iostream>

class One;

class Two {
  One* a;  // Two uses a pointer of One
};

함수의 정방향 선언은 함수를 정의하는 동안 사용될 함수의 이름과 인수에 대한 지식이 필요하고 기본 매개변수에 대한 기본값의 복제가 필요하다는 것을 기억하는 것이 가장 좋습니다.

따라서 프로그램에서 전방 선언을 사용할 때 주의해야 합니다.