C++ (1) - 연산자 , 함수 오버로드 , 템플릿 , 변수 , 동적 할당 , 파일 분할

MINO·2024년 3월 10일

C++

목록 보기
1/5
post-thumbnail

게시글을 작성하게 된 이유

C++의 장점인 클래스와 상속, 오버로드와 함수 템플릿 등 잘 활용하지 못하는 기능과 평소 궁금했거나 헷갈리는 내용을 함께 정리해보려고 한다.


참고 문헌

그림으로 배우는 C++ Programming Basic


using namespace std;

C 에서 C++ 로 넘어오면서 자연스럽게 쓰게 된 코드지만, 그 이유에 대해 딱히 생각해본 적이 없는 것 같아 찾아보았다.

C++에서는 표준 라이브러리의 모든 요소가 std라는 namespace 안에 있다. 해당 코드를 통해, "std" namespace 안의 모든 함수, 변수, 클래스 등을 이름을 명시하지 않고 직접적으로 사용할 수 있게 된다.

#include <iostream>
using namespace std;

int main()
{
	//std::cout << "First Post" << endl;
    std::cout << "First Post" << endl;
    return 0;
}

다양한 연산자

잘 사용하지 않았거나 헷갈리는 연산자 위주로 정리하였다.

  • :: (범위 확인 연산자) : 다양한 범위에서 사용되는 식별자를 식별하고 명확하게 구분하는 데 사용 (Class 및 namespace, 정적 멤버)
namespace NamespaceA{
    int x;
    class ClassA {
    public:
        int x;
    };
}

int main() {
    NamespaceA::x = 1;

    NamespaceA::ClassA a1;
    a1.x = 2;
}

Microsoft - 범위 확인 연산자 :: 에 관한 설명


  • . (멤버 참조) : union 및 class 형식의 struct 멤버에 직접 참조
  • -> (멤버 간접 참조) : 포인터를 통해 union 및 class 형식의 struct 멤버에 참조
#include <iostream>
using namespace std;

struct Date {
   Date(int i, int j, int k) : day(i), month(j), year(k){}
   int month;
   int day;
   int year;
};

int main() {
   Date mydate(1,1,1900);
   mydate.month = 2;
   cout  << mydate.month << "/" << mydate.day
         << "/" << mydate.year << endl; // 2/1/1900

   Date *mydate2 = new Date(1,1,2000);
   mydate2->month = 2; // (*mydate2).momth = 2;
   cout  << mydate2->month << "/" << mydate2->day
         << "/" << mydate2->year << endl; // 2/1/2000
   delete mydate2;
}

함수

함수 오버로드

인수의 개수 및 형이 다르면서 이름만 같은 함수를 여러 개 정의하는 행위

  • 사용 시 주의점
    - 이미 선언된 함수와 비교하여, 인수의 형(type) 또는 개수를 다르게 선언
int func1(int a);
void func2(int a); // 리턴 값의 형이 다른 경우

int func2(int a, int b = 0);
int func2(int a); // 인수의 개수가 다르지만, 기본 인수를 사용한 경우 

func1(10); // 어느 함수를 호출해야 할지 판단할 수 X
func2(10); // 마찬가지로 어느 함수를 호출해야 할지 판단할 수 X

함수 템플릿

다루는 형만 다른 함수를 틀을 통해 찍어내듯 만들어내는 기능
1. 함수 템플릿을 선언하고 정의
2. 함수를 호출 (해당 형(type)에 맞는 함수가 자동으로 생성)

다루는 형을 제외한 다른 요소가 완전히 동일한 함수에 한해 한번만 정의할 수 있음

template<class T>
T maxt(T x, T y)
{
	if(x > y)
    	return x;
    else
    	return y;
}

int max_i = maxt(1, 2);
double max_d = maxt(1.0, 2.5);

함수 오버로드 VS 함수 템플릿

다른 처리를 하는 함수들을 같은 이름으로 호출하기 위해 사용 (다형성)

기능특징
함수 오버로드함수 내부의 처리 방법이 달라도 관계없는 경우
함수 템플릿함수 내부의 처리 방법이 같아야 하는 경우, 다루는 형이 다른 경우

변수

변수의 스코프

스코프 : 변수의 이름이 통용되는 범위

다른 함수 안에 선언된 지역 변수는 같은 이름이라 할지라도 전혀 다른 변수이다.

int a = 0; // 전역 변수 a

int main()
{
	int a = 0; // 지역 변수 a
    a++; // 지역 변수 a 의 값이 증가
    
    ::a++; // 전역 변수 a 의 값이 증가
    return 0;
}

변수의 기억 수명

  1. 변수를 선언하여 메모리를 확보
  2. 변수의 값을 저장 또는 출력하여 이용
  3. 메모리를 해제 (프로그램 종료 시)

static 지역 변수와 전역 변수는 프로그램의 실행을 준비할 때부터 종료될 때까지의 기억 수명을 가진다.


동적 할당

메모리를 동적으로 확보하기

프로그래머가 원하는 타이밍에 메모리를 확보하는 방법

  1. 가변 데이터 : 실행 시점에서 필요한 메모리 양을 결정
  2. 효율적인 메모리 관리 : 필요할 때만 메모리를 할당하고 사용이 끝나면 해제함으로써 메모리를 효율적으로 관리
  3. 데이터 구조의 유연성 : 연결 리스트, 트리, 그래프을 구현하는 데 필수적입니다. 이들 구조는 런타임에 데이터 요소를 추가하거나 제거할 수 있기 때문
int *pA; // 1. 포인터를 선언
pA = new int; // 2. new 연산자로 메모리를 확보한 뒤, 주소를 대입

*pA = 50; // 메모리에 포인터로 접근하여 값을 대입

메모리를 동적으로 해제하기

메모리를 할당하고 소멸시키지 않으면 메모리를 고갈시키는 메모리 누수(Memory Leak)가 발생하고, 결국 시스템 전체의 메모리 부족 현상이 발생할 수 있다.

int main()
{
	int *pA; // 메모리를 확보
	*pA = 10;
	cout << "동적으로 확보한 메모리를 사용하여 " << *pA << " 출력하기\n";
	
    delete pA; // 메모리를 해제
    return 0;

동적으로 메모리를 할당하고 사용이 끝났다면, delete 연산자로 메모리를 해제하자. (런타임 에러의 주된 원인)


배열을 동적으로 확보하기

프로그램 실행 시 배열의 크기를 지정하여 처리할 수 있는 장점.

포인터 명 = new 형명[배열의 크기];

delete[] 포인터 명;

할당되는 메모리 영역

스택 : 지역 변수와 인수에 할당하는 메모리 영역
정적 메모리 영역 : 전역 변수 등의 정적 변수에 할당하는 영역
동적 메모리 영역 (힙) : 동적으로 할당하는 메모리 영역
nullptr : 어떠한 메모리 영역도 가리키지 않는 포인터


파일 분할

언리얼 엔진5 를 공부하며 다음과 같은 코드를 많이 접했다.

#include "CoreMinimal.h"
#include "GameFramework/Character.h"

대규모 프로그램에서 사용되는 방법으로, 자주 사용될 것이라 예상되는 함수를 다른 파일에 나누어 작성한다.
파일을 분할함으로써, 다양한 프로그램에 해당 함수를 쉽게 활용할 수 있다.

(ABPawn.h)
UCLASS()
class ARENABATTLE_API AABPawn  : public APawn
{
	...
    private:
    	void UpDown(float NewAxisValue); // 함수의 프로토타입 선언
        void LeftRight(flaot NewAxisValue);
}

(ABPawn.cpp)

#include "ABPawn.h" // 헤더 파일 읽기

...

void AABPawn::UpDown(float NewAxisValue) // 함수 정의
{
	AddMovementInput(GetActorForwardVector(),NewaxisValue);
}

void AABPawn::LeftRight(float NewAxisValue) // 함수 정의
{
	AddMovementInput(GetActorRightVector(),NewAxisValue);
}

평소 PS를 하며 써온 라이브러리는 표준 라이브러리 (standard library)이며 헤더 파일 이름을 < > 로 묶지만, 프로그래머가 작성한 헤더 파일을 인클루드할 때는 " " 로 묶어야 한다.


다양한 형

많은 PS 문제를 풀면서 typedef 와 struct 는 접했지만, enum 과 union 은 사용한 적이 없어 이번 기회에 정리해보았다.

  • typedef 형명 식별자 : 긴 형명에 별명을 붙여 코드의 가독성을 높임

  • enum 열거형명 { 식별자1, 식별자2, ... } : 식별자를 값으로 저장할 수 있는 형

  • struct 구조체형명 { 형명 식별자; ... } : 다른 형들을 하나로 묶어 저장할 수 있는 형

  • union 공용체명 { 형명 식별자; ... } : 한번에 하나의 공용체 값만 저장할 수 있는 형

typedef pair<int,int> p;
enum Week {SUN, MON, TUE, WED, THU, FRI, SAT};
struct Car {int num; double gas;};
union Year{int ad; int dangi;};

첫 게시글을 마치며

Velog 첫 게시글을 작성하며, 익숙하지 않은 마크다운 문법으로 쓰다보니 생각보다 시간이 오래 걸렸다.
항상 패드와 공책을 활용하여 정리를 하곤 했는데, Velog 를 시작하며 컴퓨터 학부에서 배운 내용과 현재 공부하고 있는 언리얼, PS 문제 등을 총 정리해봐야겠다.

아직 많이 부족한 클래스와 상속, 가상 함수 파트는 정리할 부분이 많기도 하고 코드가 많아, 다음 게시글에 정리해야겠다.

profile
안녕하세요 게임 개발하는 MINO 입니다.

0개의 댓글