• 추상화 데이터타입(abstract dadta type = ADT)

 

int, double 이런 데이터형이 아닌

사용자 정의 데이터형과 같은 느낌의 데이터형으로

 

자료구조와 많이 연관된 개념인듯하다

이러한 클래스도 추상자료형이라고 생각한다

그냥 클래스 선언부인데? 라는 생각이 들었고 이 때문에 죤내 헷갈렸는데

 

내가 생각으로는 멤버함수가 정의되지 않는다는게 중요한거 같다

 

아직 크게 감이 안오는데 나중에 다시 확인해야겠다

 

  • 객체배열의 초기화

 

초기화하는 생성자는 당연히 다른걸 써도 된다

초기화를 하지 않는 인덱스는 디폴트생성자가 실행되겠다

 


  • 클래스 사용 범위 상수

클래스 사용 범위 = 클래스 밖이 아닌 안에서 정의되는 이름에 적용

 

위의 코드에서 배열생성에 오류가 났다

이유는 a의 값을 알지 못해서인데

 

클래스선언은 클래스가 어떻게 생겼는지 서술하는것이지 객체가 생성되는건 아니다

= 객체가 생성되는게 아니니 값을 저장 할 기억 공간이 없다

= array 선언부에 a의 값은 모른다

 

그렇기에 클래스 선언부 내부에 상수를 사용하려면 두가지 방법이 있다

 

enum을 사용하는 방법

 enum은 정의만으로 메모리할당이 되지 않으며

[ 그래서 객체에 데이터 멤버를 생성하지 않는다 ]

define처럼 치환되는 방식이므로

객체가 생성되지 않아도 사용이 가능하다

 

 

static을 사용하는 방법

 

클래스 선언부 내부에 static을 사용하면 전역메모리에 올라가며 같은 클래스의 객체가 공유하고 사용 가능한

정적 멤버 변수가 된다

[정적 멤버 변수는 뒤에 자세히 나온다]

 

마찬가지로 객체의 생성과는 상관이 없기에 가능한 부분이다

 


  • enum class

C++11 에서 열거자에게 클래스 범위를 갖게하는 새로운 열거자 형식을 제공하였다

모두 enum class

열거자가 클래스 범위를 가지고 있기 때문에 저렇게 다른 enum정의의 식별자와 이름이 충돌할 가능성을 없앴다

 

단 그렇기 때문에 기존에 그냥 사용했던것과 다르게 구별할 문법이 필요한데 enumName::을 사용하면 된다

위에서 (int)로 형변환을 해준 이유는 enumClass에서 변수형 관리가 강화되었기 때문이다

기존enum처럼 일부상황에서 자동으로int형으로 암시적 전환이 이루어지지 않는다

Hand IK 를 구현 중에

 

player BP에서 Anim BP로 보내주는 sockt Location이 있다

 

이 위치에 왼손을 붙이는게 목적이였는데

 

서있을 때는 잘 되는것처럼 보였지만 달리면 계속 이전 프레임의 Location을 받아오고

시간을 느리게하면 잘 붙어서 정말 뭔가했다

 

달리면 손이 손잡이에 붙지 않는다 씨빠!

 

이전 프레임의 값을 받는다는건 Tick의 순서가 내가 원하는 순서가 아님에 분명하다라는 생각이 들었다

 

열심히 검색 후 틱그룹 이라는 걸 알게된 후 이걸로 해결했다

https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Actors/Ticking/

 

액터 틱

매 프레임 액터를 업데이트하는 데 사용되는 Tick, 틱 시스템에 대한 설명입니다.

docs.unrealengine.com

 

나중에 한번 포스팅해야겠다

 

클래스 디폴트에 들어가 액터의 틱을 변경 할 수 있다

근데 나는 액터의 틱그룹이 아닌 Anim BP의 틱그룹을 변경해야했다

 

그래서 Anim Bp의 클래스 디폴트창을 보았지만 없어서 변경하는 법을 찾았다

 

Anim BP를 사용하는 Mesh에서 찾을 수 있다

 

 

Anim BP를 사용하는 컴포넌트(나의 경우 SkeletalMesh Component) 의 틱그룹을 변경해주면 

 

Anim BP의 틱그룹도 같이 변경됐다.

 

해결 후 잘 붙어있다
  • 클래스 생성자

개념 : 객체가 생성될때 호출되는 함수

생성자가 없다면 객체는 생성 될 수 없다

 

아무래도 생성될 때 호출이 되다보니 초기화 기능과 굉장히 잘 부합한다

생성자의 이름은 클래스 이름과 같고 리턴 자료형이 없음에도 void를 기술하지 않는다

 

생성자의 호출에 있어서 명시적호출, 암시적호출이 있다

생성자 함수명의 유무에 차이가 있는듯하다

 

소괄호가 아닌 중괄호로 초기화 한 부분은 리스트 초기화 구문이다

중괄호 안의 값들과 생성자의 매개변수들을 매칭시켜주는 것

 

생성자는 오버로딩도 가능하다

객체의 여러가지 초기화 버전을 갖출 수 있겠다

 


  • 디폴트 생성자

개념 : 매개변수를 기술하지 않아도 되는 생성자

 

디폴트 생성자는 암시적 버전과 명시적 버전이 있다

 

암시적 버전

 

생성자를 작성하지 않으면 C++에서 자동으로 생성자를 만들어 호출해준다

물론 아무일도 하지않는다

[ 사용자 정의 생성자를 작성하면 자동으로 생성되지 않는다 

=  초기화되지 않은 객체의 생성을 사용자가 원하지 않을 수도 있기 때문]

 

명시적 버전

 

사용자 정의 생성자로 매개변수를 기술하지 않아도 호출될 수 있는 생성자를 뜻한다

 

이는 두가지가 있다

사용자는 하나의 디폴트 생성자만 가질수가 있다

 

그렇기 때문에 저 두 생성자를 동시에 사용 할 수 없다

 

주의할 점 하나는 암시적으로 생성자를 사용할 때 소괄호를 사용하면 안된다

"cout<< 생성됨" 이 출력되지 않음

 

이 디폴트 생성자의 필요성은 클래스 배열을 생성할때 꼭 필요하다는 점이다


  • 파괴자

개념 : 객체의 수명이 끝날 때 자동으로 호출이 됨

         객체의 흔적을 지우는 역할과 잘 부합한다

 

생성자와 마찬가지로 사용자 정의 파괴자가 없다면 자동으로 디폴트 파괴자를 생성하여 호출한다

그리고 파괴자는 매개변수를 가지지 못한다

 

파괴자의 호출은 일반적으로 사용자가 코드에 명시적으로 호출하지 않는다

(뒤에 나오는 한가지 예외가 있다고한다)

 

객체의 기억공간에서 벗어난다면 자동으로 호출이 된다

 


  • 내가 헷갈릴만한 것

임시객체부분

결과

선언과 동시에 생성자를 쓰는 부분은 생성자가 한번 호출 된다

[ 컴파일러에 따라 임시객체의 생성 유무가 다르다. 내가 사용하는 환경은 임시객체를 생성하지 않는다 ]

 

선언이 아닌 대입으로 생성자를 사용하는 부분은 임시객체를 생성하고 대입 후 파괴한다

[ 단 이건 컴파일러에 따라 임시객체를 유지하는 시간이 다르다 ]

 

 

생성자만 호출

생성자만 호출되어도 객체가 생성됨


  • const 멤버 함수

 

객체 Test는 값이 변경되면 안되는 const 객체이다

 

컴파일러가 보기에 이 Test객체의 TestFunc이 값을 변경하는지 안하는지 모르니까 컴파일러는 에러를 띄워준다

 

그래서 이 함수는 값을 변경하지 않으니까 안심해 라는 뜻으로 함수선언 소괄호 뒤에 const를 붙여준다

 

const멤버함수를 선언하고 멤버함수의 값을 변경하면 당연히 안된다

 


  • this포인터

객체의 멤버함수들은 기본적으로 this라는 숨은 매개변수를 가지고 있다

 

멤버함수를 호출하면 호출 된 멤버함수는 자신을 호출한 객체를 포인터로 매개변수로 받아오는데

그것을 사용하는게 this 이다

함수 내부에 자동으로 ClassName * const 형으로 선언됨

 

예로 어떠한 상황에서 자기자신을 리턴해주는 경우가 필요한데 이때 사용이 가능하다

 

  • 추상화

'코끼리 상'은 '형상 상' 이라는 이름도 가지고 있다

사물의 어떠한 공통적인 특징을 추출하여 파악

 

내가 생각하기에는 객체의 목적을 공통으로하여 기능들을 추출하는것이 추상화라 생각한다

 

 


  • 클래스

추상화한 것을 사용자 정의 데이터형으로 변환한것

 


  • 사용자 범위 결정 연산자

:: 인데 namespace관련해서도 사용했었다

 

클래스의 멤버함수를 정의 할 때

정의부 함수 머리에 클래스이름::함수이름( ) 이런식으로 사용하는데

이때의 :: 가 이 함수는 이 클래스의 멤버함수라는것을 나타내며

클래스 사용범위 라는걸 알려준다

 


  • 인라인 메서드

클래스 선언 안에 정의를 가지고 있는 모든 함수는 자동으로 인라인 함수가 된다

 

 


  • 멤버함수

같은 클래스로 여러객체를 생성하면 각 객체는 변수들을 위한 각각의 저장 공간을 가진다

 

그러나 메서드는 이렇게 각각 저장을 하지 않고 한곳에 저장된다

 

왜냐하면 함수의 구조가 변경된다던지 이런 일이 없기 때문에 굳이 각각 저장하지 않는거같다

 

멤버함수는 멤버변수와 같이 정적, 비정적이 존재하며 둘다 모두 code영역에 저장이 되며

(저장되는 타이밍은 다르다)

 

같은 클래스에서 나온 객체끼리 모두 공유하면서 사용한다!

 

 

 

 

먼저 UE_LOG를 통한 로그는 게임 화면이 아닌 출력 로그 창에서 확인 할 수 있다

 

UE_LOG는 매크로로 설정되어있고 사용시 3개의 매개변수가 필요하다

 

1. LOG Category

더보기

어느 부분에서 일어난 로그인지 확인 할 수 있는 카테고리

 

카테고리는 직접 만들수 있으며 기본적으로 제공하는 카테고리를(ex LogTemp) 사용 할 수도 있다

기본 카테고리 + 작성한 카테고리 확인 가능

 

카테고리 생성관련 세가지 함수가 있다

FLogCategory를 만들어 내는거 같다

https://docs.unrealengine.com/4.26/en-US/API/Runtime/Core/Logging/FLogCategory/

 

 

  • DECLARE_LOG_CATEGORY_EXTERN( 만들카테고리명, DefaultVerbosity, CompileTimeVerbosity )

만들 카테고리명을 선언(Declare)한다는 느낌이다

뒤에 EXTERN때문에 이게 정의된걸 가져오는 느낌을 처음에 많이 받았었는데

사용해본 결과 이 함수가 무조건 나와줘야 정의가 가능했기에 선언으로 생각하고있다

 

2번째와 3번째 매개변수는 같은 Enum형식(ELogVerbosity)을 매개변수로 받는다

https://docs.unrealengine.com/4.26/en-US/API/Runtime/Core/Logging/ELogVerbosity__Type/

 

verbosity : 다변
다변 : 말이 많음(?) ㅋㅋㅋㅋ

말이 많다는게 상세한 정보를 그만큼 나타낸다는 의미같다

 

이 verbosity 속성이 이해가 잘 안되서 찾다가

밑의 사이트를 보았는데 자세히 설명이 되어있었다

https://unrealcommunity.wiki/logging-lgpidy6i

 

아직 잘 모르겠다 시발 이거 너무 어렵다

 

이해한걸로는 프로그램에 기본 verbosity Level이 있고

그 level 보다 더 높으면 그 로그문은 게임코드로 컴파일되지않고 무시된다 라는 말인데

이렇게 조절함으로 로깅을 할때 나오는 세부정보 수준을 조절해 원하는 정보만 골라보는것이다

 

로그의 세부정보가 뭔지를 잘 모르겠다

로그의 세부정보 단계라고 하면 이해할거같은데

일단 여기까지 봐야할듯하다 존내 봐도 모르겠어서 넘 시간 많이 뺏김 계속 생각해봐야할듯

https://unrealcommunity.wiki/logs-printing-messages-to-yourself-during-runtime-n5ifosqc

여기 한번 보기

 

  • DEFINE_LOG_CATEGORY( 만들카테고리명 );

위의 DECLARE_LOG_CATEGORY_EXTERN(이하 EXTERN) 과 무조건 같이 써주어야하는 함수이다

 

DECLARE_LOG_CATEGORY_EXTERN으로 선언을 하고 정의를 이 DEFINE_LOG_CATEGORY(이하DEFINE)에서 하는것이다

 

그래서 보통 선언을 헤더파일에 하듯이 헤더파일에 EXTERN을 넣고

이 카테고리를 써줄 파일에 include하는 형식으로 사용하는거 같고

 

정의는 한번만 해야하기에 CPP 파일에 DEFINE을 사용하는거 같다

 

그래서 테스트로 실행해 봤다

잘 나온다

 

  • DEFINE_LOG_CATEGORY_STATIC

감 잡은 사람도 있겠지만 STATIC이 붙어 내부링크속성을 가진다

 

다른 파일에서는 사용할 수 없다는 뜻

 

만들기에는 이 함수 하나만 사용해도 되어 편하다

 

입맛에 맞춰 

DECLARE_LOG_CATEGORY_EXTERN

DEFINE_LOG_CATEGORY

를 사용해 범용적으로 사용할건지

 

DEFINE_LOG_CATEGORY_STATIC

를 사용해 단일 파일에 간단하게 사용할건지 선택하면 되겠다

 

 

2. LOG Level

위에 vorbosity의 ENUM형과 같다

 

 

3. 로그로 띄울 메세지

printf를 사용하듯이 사용하면된다

컴파일러가 유니코드로 실행된다면 유니코드로 만들어줘야한다 (TEXT or L 을 붙이기)

 

형식이다

  • 위치지정 new

개념 : 사용할 위치를 사용자가 지정할 수 있다

 

이 위치란 말이 처음에는 헷갈렸는데 주소라고 변경해도 될거같다

사용법은 new의 매개변수에 사용할 주소를 추가로 넣어주면 된다

 

대부분 예로 드는 예제
이렇게도 가능하다

기존 new는 힙에서 할당을 해오지만

위치지정 new는 메모리 관리를 모두 개발자에게 맡기기 때문에

힙영역, 정적영역, 스택영역의 메모리에도 지정할 수 있었다.

 

메모리 해제 같은 경우 참조한 메모리의 영역에 맞추어 하면 된다.

힙 같은 경우는 사용자가 해제 해주어야 하니 delete를 써주면 되고

정적, 스택 영역 같은 경우는 자동으로 해제되니 맡기면 된다.

 

맨 위에서 2번째 예시의 코드의 int * pa = new (&a) int; 는 사실 int * pa = &a; 와 같아 보이는데

이처럼 그냥 대입하면 되지 왜 만들었을까 생각을 했다

https://ehei.tistory.com/505
이런 기능이 필요한 이유는 다음과 같다. 힙을 할당하는 건 많은 비용이 든다. 메모리의 정합성을 유지하기 위해 운영체제가 수행해야하는 작업이 있다. 가상 메모리, 페이지 단위 관리, 그리고 메모리 파편화를 피하기 위한 재배치가 그런 것들의 예이다. 여기에 드는 비용은 프로그래머가 예상할 수 없다. 그러나 발생하면 치명적이다. 정체불명의 랙이 생길 수도 있다. 따라서 보통은 메모리풀이란 개념으로 대량의 연속된 메모리를 할당받는다. 그리고 위치지정 new를 이용하여 객체를 그곳에 생성한다

 

다른 생성자 문제도 있겠으나 이렇게 메모리 관리를 위해 사용하는 느낌이 더 강하게 왔고

메모리 풀에도 쓰인다하니 나중에 더 알게될듯 하다.

 


  • 선언영역 & 잠재 사용 범위

선언영역(declarative region) : 선언을 할 수 있는 영역

 

ex) 어떤 변수를 함수 밖에 선언한다면 선언영역은 선언된 파일이다

     어떤 변수를 함수 안에 선언한다면 선언영역은 선언된 블록이다

 

잠재 사용 범위(potential scope) : 간단히 사용 영역

 

ex) 변수를 함수안에 선언하면 잠재 사용 범위는 "변수 선언 ~ 함수 끝" 이다

 

 


  • 이름 공간

 

전역 이름 공간 - 우리가 보통 전역변수를 생성할때 이 전역 이름 공간에 만들고 있었다

 

namespace - 사용자가 정의하는 이름 공간

 

이 namespace는 무조건 전역이름공간에 생성될수밖에 없기 때문에

안에 들어있는 변수나 함수는 전역적 속성을 가진다

 

 

namespace이지만 이름이 생략된 공간 - 내부링크속성을 띄는 정적변수라 볼수있다

 


  • using선언 & using지시

using 선언 :  간단히 이름공간 안에 있는 하나의 변수, 혹은 함수를 using이 사용된 공간에 사용한다는 뜻

단 짚고 넘어가야할 것은 지역이름 공간에 넣는다는 뜻이다

이렇게 선언한 식별자는 같은 공간내에 중복으로 선언 불가능해진다

이유는 위에 언급했듯이 지역이름공간에 넣기때문에 그렇다

아직은 문제 없지만
실행시 에러

 

 

using 지시 : namespcae 전체를 접근하게 한다

주의할 점은 using선언과 달리 전역적으로 사용한다는 것이다

 

using + namspace로 사용

위에서 언급했듯이 선언과는 다르게 이렇게도 가능하다

 

mySpace에 소속된 space1과 같은 식별자를 지역변수로 선언 할 수 있다

 

이 부분이 굉장히 헷갈렸었는데

위에서 말했듯이 선언은 지역이름공간에 넣어주고

지시는 전역적으로 사용하게끔 하기 때문에 이런 차이가 날 수 있게 된것이다.

 

  • thread_local

변수의 존속시간이 쓰레드의 존속 시간과 같다는 제한자

 

존속시간은 예를들어

정적 변수의 존속시간은 프로그램이 실행되고 종료될때까지이다

 


  • volatile
volatile : 변덕스러운
변덕 : 이랬다저랬다 잘 변하는 태도나 성질

개념 : 간단히는 최적화를 수행하지 못하게 막는다, 라고 할수있고

         자세히는 volatile 변수를 참조할때 레지스터에 로드 된 값을 사용하지 않고 항상 메모리를 직접 참조 한다

 

최적화를 왜 막아야하는가? 

최적화로 인해서 생략된 코드때문에 개발자가 의도한대로 흘러가지 않는 경우도 있는 듯 하다

 

https://luna-archive.tistory.com/2

 

[C] 임베디드 시스템에서 volatile 키워드를 사용하는 이유

MCU 프로그래밍을 하다 보면 레지스터를 제어하기 위해 같은 주소에 여러번 값을 여러번 쓰는 경우가 빈번하고, 이런 경우 코드를 보면 앞에 volatile 키워드를 사용하는 경우를 볼 수 있다. 처음

luna-archive.tistory.com

https://blog.naver.com/PostView.nhn?isHttpsRedirect=true&blogId=classic2u&logNo=50003118713&parentCategoryNo=&categoryNo=15&viewDate=&isShowPopularPosts=false&from=postView

 

이 두 글에 자세히 나와있다

 

최적화가 일어나지 않으므로 코드가 생략되지 않고 모두 직접 메모리에 실행되어 값이 변할수도 있기에

변덕스러운 이라는 뜻이 어울린다고 생각한다

 

일단 이 개념은 여기까지

 


  • mutable

개념 : const 구조체 또는 const 클래스의 멤버지만 변경가능한 멤버변수를 선언할때 사용한다

 

 


  • const의 내부링크

기본 전역 변수는 외부링크로 디폴트가 되어있다

 

하지만 const가 붙으면 내부링크로 변경된다

 


  • 함수와 링크

함수역시 링크 속성을 가진다

 

모든 함수는 정적기억존속을 가진다.(프로그램의 시작과 끝까지) = 외부링크

 

static을 사용하여 내부링크를 부여 할 수 있다

 


  • 단일 정의 규칙

프로그램은 인라인이 아닌 모든 함수에 대해서 정확히 하나의 정의만을 가져야한다

+ Recent posts