[C++] 포인터, 값에 의한 전달, 주소에 의한 전달, 참조에 의한 전달에 대한 이야기


메모리에는 위치를 구분하기 위해 0번지부터 시작해서 일련번호가 붙여져 있는데 이것을 주소(어드레스)라고 한다.

주소는 정수 형태이며 단위는 바이트이다. 컴퓨터가 데이터를 처리하려면 먼저 데이터를 메모리(램)으로 옮겨야한다.


포인터란?


컴퓨터의 메모리 번지(address)로, 데이터가 어디에 저장되어 있는지를 알려준다. C++에서는 이 포인터(변수의 주소)를 직접 사용할 수 있도록 포인터 연산자(&)를 제공한다.


& - 주소

* - 값



포인터 변수?


주소만을 저장한다. 포인터 변수는 선언할 때 반드시 기호를 덧붙여야 한다. 포인터 변수를 단독적으로 p라고 사용하는 것은 포인터값(주소)를 의미하지만, 포인터 변수에 *를 덧붙인 *p는 더 이상 주소가 아니라 해당 주소에 저장된 값을 의미한다.

그래서 p에는 변수 a의 주소가 저장되어 있으므로 *p는 변수 a의 값을 출력한다.


대입 연산자로 값을 대입할 경우 대입 연산자 오른쪽과 왼쪽에 오는 자료형이 같아야 한다.



매개변수의 전달?


함수에 사용될 데이터를 보내는 방법이다.



전달하는 방법 3가지


1. 에 의한 전달 방식( Call by Value)

2. 주소에 의한 전달 방식( Call by Address)

3. 참조에 의한 전달 방식( Call by Reference)



1. 값에 의한 전달 방식( Call by Value)


호출 측의 실 매개변수는 함수 측으로 값만 전달한다.
함수 측에서는 형식 매개변수가 실 매개변수와 별도로 기억공간을 할당받고 그 곳에 실 매개변수에 저장되었던 값만 전달받아 복사
이 방식은 별개의 기억공간이 사용되므로 실 매개변수의 값은 변경되지 않아요.
바꾸고 싶다면 return값을 이용하세요.


2. 주소에 의한 전달 방식( Call by Address)


실 매개변수로 변수의 주소값을 넘겨주고, 형식 매개변수가 이를 포인터 변수에 저장하도록 한다.



* 3. 참조에 의한 전달 방식( Call by Reference)

C++에 추가된 것 중에 하나가 레퍼런스(참조)변수이다. 레퍼런스 변수란 별명(일종의 다른이름)을 의미한다. 레퍼런스 변수는 따로 기억공간이 할당되지 않는다. 메모리 상에 오로지 하나만 존재하고, 여러 이름으로 접근해서 사용할 수 있도록 한다.

자료형 & 별명 = 변수_이름;

<< 이렇게 선언하는 것 말고는 일반 변수처럼 사용하면된다. *,&이런거 생각할 필요가 없어요!  >>

이때 사용된 &기호는 참조 연산자라고 한다.
따라서 변수 선언시 & 기호가 사용된 경우 - 참조 연산자
선언이 끝난 변수에 사용되는 & 기호가 사용된 경우 - 주소 연산자

*레퍼런스 변수를 선언할 때 주의할 점은 반드시 변수 선언시 초기값을 주어야 한다는 것이다.


[C++] 기억클래스에 대한 이야기(자동변수 auto, 외부변수 extern , 정적변수 static, 레지스터 변수 register)

블록내 선언 - 지역변수

블록 외부에 선언 - 전역변수


변수 선언이 의미하는 것은? 메모리에 기억공간, 영역을 확보하기 위해서이다.



변수를 어떻게 선언하느냐에 따라서 유효 범위와 생존기간 등 변수의 성격이 달라진다.

변수의 기억공간을 얼마만큼 확보할 것인지는 자료형에 의해서 결정된다.



유효 범위와 생존 기간을 결정하는것은 기억 클래스이다.


 기억 클래스

유효범위 (scope) 

생존 기간

메모리

초기화 여부 

auto(지역 변수) 

블록 내

일시적 

stack 

쓰레기 값 

extern(외부 변수) 

프로그램 내 

영구적 

메모리

숫자 0 

static(정적 변수)

내부 : 블록 내

외부 : 모듈 내 

영구적 

메모리 

숫자 0 

 register(레지스터)

블록 내 

일시적 

CPU 내의 레지스터 

쓰레기 값 


일반적으로 변수는 기억클래스가 생략된다.

[기억클래스] 자료형 변수명;

변수 선언은 자료형과 기억클래스에 의해 다음 2 가지로 구분가능하다.

 자료형에 의한 구분

int, char, float 등

생략 불가 

저장되는 값의 형태와 

기억공간의 크기를 결정 

기억클래스에 의한 구분 

auto, extern, static 

생략시 auto로 인식

유효범위와 생존 기간을 결정 



자동 변수 auto


 프로그램이 실행되는 동안 생성과 소멸을 반복한다. 선언된 문장을 만나면 메모리 할당이 일어나므로 변수 선언문 이후에서만 사용가능하고, 변수 선언이 된 블록 밖으로 벗어나면 메모리가 해제되어 변수를 사용할 수 없다.



자동변수와 스택


 컴파일러는 자동변수가 선언되면 스택에 메모리 할당을 한다.

 스택은 LIFO구조로 메모리의 일부를 잡아 새로 생성되는 변수들을 차곡차곡 쌓아두었다가 맨 위 (가장 최근에 선언된)에 있는 변수가 사용된다. 제거 할 때에도 맨 위에 있는 것부터 제거한다.


외부 변수 


블록(함수)안에 선언된 변수를 지역변수라 하며 변수를 사용할 수 있는  범위는 그 변수가 선언된 블록 내부로 한정된다. 자동변수는 대표적인 지역변수이다. 변수 선언 함수 외부에서 하는 경우가 있다. 이러한 변수들을 전역변수라고 한다. 외부변수는 대표적인 전역변수로 프로그램 내의 모든 함수에서 사용할 수 있는 변수이다. 외부변수는 프로그램이 실행되는 동안 메모리 상에 항상 배치되므로 값이 유지된다.



지역 변수와 전역 변수


main 함수 내에 선언한 지역변수들은 main 함수 내에서만 사용가능하기 때문에 사용자 정의 함수에서는 사용할 수 없다.

그래서 함수에 매개변수가 있는 것이다. 또한 main 함수에 선언된 변수값을 사용자 정의 함수에서 변경하기 위해서는 단순히 인수만을 사용하는 것만으로는 불가능하다.

포인터나 레퍼런스 변수를 사용하여 Call By Address나 Call By Reference 기법을 사용해야만 가능하다. 이러한 여러 가지 방법을 사용해야 원하는 결과를 얻는 이유는 변수를 지역변수로 선언하였기 때문이다.


전역변수는 인수를 사용하지 않고도 모든 함수에서 사용가능하므로 매우 호감이 간다. 하지만 이러한 전역변수는 쉽고 간단한 접근을 허용하는 대신 프로그램의 신뢰성에 큰 위협을 가한다. 변수값이 어디서나 변경 가능하다는 것은 그 만큼 위험 부담을 안고 있으므로 값비싼 대가를 치러야 할지도 모른다. 좋은 프로그램을 작성하기 위해서는 데이터의 무결성이 잘 보존되도록 데이터를 필요한 경우에만 접근할 수 있도록 격리시켜야 한다. 전역변수도 나름대로 필요하겠지만 편리성을 이유로 부분별하게 사용해서는 안된다.



auto 지역변수 VS extern 전역변수


지역변수가 우선이고, 없으면 전역변수로 !




정적 변수


변수를 선언할 때 변수 이름 앞에 static을 붙이면 정적변수로 선언된다.

지역변수로서의 정적변수와
전역변수로서의 정적변수가 있다.
이에 대한 구분은 변수선언을 어디에 했는지 위치에 의해 결정된다. 블록 내부에 선언되면 지역변수로서의 정적변수이고, 블록 외부에서 선언하면 전역변수로서의 정적변수가 된다.


지역변수로서의 정적 변수는 함수 내부에 선언하고, 그 함수 내에서만 사용가능하다.



자동 변수 vs 정적 변수


자동변수는 생성과 소멸을 반복하므로 스택과 같은 특별한 메모리를 사용하지만 정적변수는 프로그램이 시작하는 시점에서 메모리 영역에 고정적으로 할당된다. 정적변수는 함수의 호출과 상관없이 프로그램이 시작되는 순간 변수가 생성되고, 초기화도 이 때 한번만 한다. 정적변수가 선언된 함수의 실행이 종료되어도 소멸되지 않고 메모리에 그 값이 기억되어 있다.



전역변수로서의 정적변수


전역변수는 함수 외부에서 선언하는 외부변수이다. 프로젝트로 묶여있는 모든 파일 내에서 공유해서 사용할 수 있는 변수가 외부변수이다. 하나의 파일에서는 아무런 조건 없이 외부변수를 가져다 사용할 수 있지만, 다른 파일에서 그 변수를 공유하여 사용하려면 참조 선언을 하여야 한다.



하나의 파일은 static

프로젝트로 여러개의 파일에서 쓸려면 extern



extern 자료형 변수명; 초기값은 줄 수 없다!


어떤 파일에 선언된 외부 변수를 다른 파일에서 접근해서 사용하려면 지정어 extern을 기술하여야한다. extern을 지정하지 않으면 다른 파일에 정의된 외부변수를 사용할 수 없다. 전역정적변수는 그 변수가 선언되어 있는 파일에서만 사용 가능한 전역변수이다. 단 하나의 파일에서만 사용할 수 있는 전역변수가 필요하다면 함수 외부에 변수 선언 시 static을 붙인다.



다른 파일에서의 extern의 의미는 따로 기억공간을 할당 받는 것이 아니라 이미 다른 파일에 선언된 변수를 참조하겠다는 의미이다. 이때 주의할 점은 extern이 붙은 변수 선언에서는 초기값을 줄 수 없다는 점이다.


static으로 선언된 변수를 extern으로 부를 순 없나봅니다.


레지스터 변수


모든 면에서 자동변수와 동일하다.

단, 더빠르다는 것!


 자동변수

스택 (Stack) 

 레지스터 변수

CPU 내의 레지스터 


하지만, CPU 내의 레지스터는 제한되어 있으므로 기억클래스 register를 붙이더라도 레지스터가 여분이 없을 경우 자동변수처럼 스택에 자리를 잡는다.



[C++] 클래스의 설계

 

절차적 프로그래밍

 

C언어가 대표적인 절차적 프로그래밍 언어이다. 절차적 프로그래밍의 언어는 프로그램의 시작을 주도하는 main함수 내에 기술된 내용이 순차적으로 수행된다. 그래서 main 함수는 대부분 다른 함수의 호출로 기술되어 있다. 이처럼 절차적 프로그래밍에서는 함수를 중심으로 프로그램을 설계한 후 거기에 필요한 데이터를 정의한다.

 

 

객체지향 프로그래밍

 

객체를 지향하는 프로그램 방식으로 객체를 생성하기 위한 클래스를 설계한 후에 이를 다룰 메소드(사용자 인터페이스)를 정의하여 메소드로 객체를 다루도록 한다.

 

일정한 순서에 의해 진행되지 않는다.

사건이 일어날 때마다 그에 따른 처리를 하는 식이다.

여기서의 객체는 구조체처럼 멤버변수를 가지고 있으면서 그들만의 함수도 함께 가지고 있는 것을 말한다.

객체 내부에 정의된 함수는 그 객체를 사용하기 위해 필요한 기술적인 측면을 모두 정의하고 있고, 메소드라 한다.

 

 

객체 지향 프로그래밍의 특징

 

1. 캡슐화와 데이터 은닉

 

데이터를 직접 다루면 손상될 수 있으므로 이를 방지하기 위해 제공되는 것이 캡슐화(Encapsulation)와 데이터은닉(Data Hiding)이다. 사용자가 데이터를 직접 사용하지 못하게 하고, 대신 메소드를 통해서 접근 가능하도록 함으로써 데이터의 유효성을 검증한다.

 

 

2. 다형성과 함수의 오버로딩, 연산자 오버로딩


다형성( Polymorphism)은 동일한 함수나 연산자를 자료에 따라 다르게 동작하도록 적용할 수 있음을 의미.

예를 들어, 함수의 이름은 동일한데 매개변수의 자료형이나 개수를 서로 다르게 주어 여러번 정의할 수 있는데 이를 함수의 오버로딩이라고 한다.

특히 C++에서는 연산자를 정의할 수 있다.

이미 사용 중인 연산다를 다른 용도로 다시 정의해 사용할 수 있는데 이를 연산자의 오버로딩(Operator Overloading)이라고 한다.

 

3. 상속성

상속성(Inheritance)은 객체지향의 가장 대표적인 특징으로, 특정 객체의 성격을 다른 객체가 상속받아 사용할 수 있도록 하는 것이다. 클래스를 설계할 때 여러 개의 클래스에 공통적으로 필요한 성격을 가장 기본적인 클래스에 정의해 두는데, 이 기본적인 클래스를 부모 클래스라 한다.

상속은 이미 존재하는 클래스의 상속을 받기 때문에 매번 전체를 다시 만들 필요없어 개발 기간을 단축시키고 기존 코드를 재활용할 수 있다.

 

 

 

class는 자료를 추상화하여 사용자정의 자료형으로 구현할 수 있도록 하는 C++의 도구이다.

class로 클래스를 선언하는 형식은 구조체와 유사하지만 개념은 확연히 다르다.

 

구조체는 단순히 멤버변수들을 정의하여 원하는 형태로 기억공간을 할당받을 수 있도록 정의하는 것.

클래스는 기억공간을 확보하는 것은 물론이고 이 클래스를 다룰 수 있는 방법도 구현해야 한다.

 

클래스는 크게 클래스 선언과 클래스 멤버함수의 정의로 구성되어 있다.

클래스 선언에는 멤버변수와 멤버함수 원형(프로토타입)을 기술한다.

멤버함수의 정의는 클래스 선언 밖에서 따로 이루어진다.

 

<<클래스 선언>>

 

class 클래스명
{

접근 지정자 :

자료형 멤버변수;

접근 지정자:

자료형 멤버함수();

}

 

 

 

<<멤버함수 정의>>

 

자료형 클래스명::멤버함수()

{

}

 

클래스의 선언은 구조체 선언과 그 구조가 비슷하지만 구조체에는 없었던 접근 지정자가 추가된다.

 

private로 선언된 멤버는 해당 멤버가 속한 클래스의 멤버함수에서만 사용할 수 있기 때문에 캡슐화(데이터은닉) 된다.

public 으로 선언된 멤버들은 객체를 사용할 수 있는 범위라면 어디서나 접근이 가능한 공개된 멤버. 주로 private 멤버를 해당 클래스 외부에서 사용하도록 하기 위한 멤버함수를 정의할 때 사용한다.

 

 

클래스는 새로운 자료형으로 설계할 때는 단순히 데이터의 저장 측면뿐만 아니라 데이터를 처리할 메소드(멤버함수) 제공도 고려해야 한다.

그러므로 다음과 같이 클래스는 새로운 자료형이 되고, 데이터는 멤버변수가, 데이터를 처리할 메소드는 멤버함수가 된다.

 

데이터 은닉에 입각해 멤버변수의 접근지정자는 private로 선언하는 것이 일반적이다.

private로 선언된 멤버현수는 직접제어하지 못하므로 이를 다룰 수 있도록 하기 위한 방법으로 제공하는 멤버함수는 클래스 외부에서 접근 가능하도록 하기 위해서 접근 지정자를 public으로 선언하는 것이 일반적.

 

 

 

클래스의 멤버함수 구현


함수의 3요소는 함수의 정의, 선언, 호출이다.

멤버함수도 이 3가지 조건을 만족해야하며, 멤버함수의 호출은 일반함수와 달리 클래스로 객체를 선언하여 인스턴스화되어야 호출할 수 있다.

 

1. 정의할 때 그 함수가 어느 클래스에 소속되는지 나타내기 위해 함수명 앞에 클래스명을 명시한다. 이때 클래스명 다음에 스코프 연산자(::)를 사용한다.

2. 정의하는 목적은 클래스 내에 정의된 private멤버에 접근하여 이를 다루기 위해서이다. 그래서 멤버함수를 메소드라고도 한다.

 

 

만약 함수를 정의할 때 소속된 클래스명이 명시되어 있지 않기 때문에 이 함수는 일반 함수로 인식한다.

클래스명을 명시하는 것은 어느 클래스에 소속되어 있는지를 식별하기 위해서이지만

다른 클래스에서 같은 이름의 멤버함수를 사용할 수 있도록 하기 위해서이기도 하다.

 

private멤버변수는 자신이 속한 클래스의 멤버함수를 제외하고는 다른 어떠한 함수에서도 접근할 수 없다.

그렇다고 멤버변수를 public으로 선언하면 이는 객체지향 개념에서 벗어난 클래스 설계가 된다.

 

 

객체는 클래스를 실체(Instance)화한 것이다. 그래서 객체를 인스턴스(Instance)라고도 한다.

 

 

Ex> int a

 

int : 자료형

a   : 객체

즉 자료형 int는 a변수를 만들어내기 위한 형틀 !

즉, 템플릿(Template)이다.

 

클래스도 객체를 생성하기 위한 하나의 형틀로 이해하면 쉽다.

 

 

 

 

 

 

[자료구조] 자료구조 & 알고리즘에 대한 짧은 이야기

 일상생활에서의 예

 해당하는 자료 구조

 물건을 쌓아놓는 것

 스택

 영화관 매표소의 줄

 큐

 할일 리스트

 리스트

 영어사전

 사전, 탐색구조

 지도

 그래프

 조직도

트리 


 

자료구조는 알고리즘 + 프로그램 이다. 프로그램에서 자료(data)를 처리하고 있고 이들 자료는 자료구조(data structure)를 사용하여 표현되고 저장된다. 또한 주어진 문제를 처리하는 절차가 필요하다. 이것은 알고리즘(algorithm)이라고 불린다.

 

자료 구조가 결정되면 그 자료 구조에서 사용할 수 있는 알고리즘이 결정된다.

 

 

알고리즘이란 문제와 컴퓨터가 주어진 상태에서 문제를 해결하는 방법을 정밀하게 장치가 이해할 수 있는 언어로 기술한 것이다.

 

알고리즘 조건은 무엇일까?


 1. 입력

0개 이상의 입력이 존재한다. 

 2. 출력

1개 이상의 출력이 존재한다.

 3. 명백성

각 명령어의 의미는 모호하지 않고 명확해야 한다. 

 4. 유한성

한정된 수의 단계 후에는 반드시 종료되어야 한다. 

 5. 유효성

각 명령어들은 실행 가능한 연산이어야 한다. 


 

알고리즘을 기술하는데 유사코드(preudo-code) , 프로그래밍 언어가 가장 많이 쓰인다.

 

유사코드는 흔히 알고리즘을 기술하는데 선호되는 표기법이다.

 

EX> 최대 값을 찾는 알고리즘을 유사코드로 표현

ArrayMax(A,n)

 

tmp <-- A[0];

for i <-- 1 to n-1 to

if tmp < A[i] then

tmp <-- A[i];

return tmp;

 

 

tmp = A[0];

for(int i = 1 ; i<n-1; i++)
{

if(tmp < A[i])

{

tmp = A[i];

}


}

 

 

프로그램에서 데이터(data)란 처리의 대상이 되는 모든 것을 말한다.

데이터 타입(data type)? 데이터의 집합과 이러한 데이터에 적용할 수 있는 연산의 집합을 의미한다.

 

 

추상화란, 어떤 시스템의 간략화된 기술 또는 명세로서 시스템의 정말 핵심적인 구조나 동작에만 집중하는 것이다.

 

추상 데이터 타입이란 새로운 데이터 타입을 추상적으로 정의한 것이며, 자료 구조를 추상적, 수학적으로 정의한것이다.

추상데이터 타입은 많은 장점을 가지고 있으니까  거부감 갖지말고.. 무서워 하지말자...

 

자료구조 (data structure)는 이러한 추상 데이터 타입을 프로그래밍 언어로 구현한 것이라 할 수 있다.

 

좋은 추상화는 어떤것일까?

사용자에게 중요한 정보는 강조되고 반면 중요하지 않은 구현 세부 사항은 제거되는 것이다.

이를 위하여 정보은닉기법(information hiding)이 개발되었고 추상 데이터 타입의 개념으로 발전 되었다.

 

추상 데이터 타입(abstract data type: ADT)은 데이터 타입의 프로그램이 그 데이터 타입의 구현으로부터 분리된 데이터 타입을 말한다. 즉, 데이터 타입을 추상적으로 정의함을 의미한다. 데이터의 집합과 데이터에 가해지는 연산들의 집합의 수학적인 명세이다.

 

효율적인 알고리즘이란 결과가 나올 때까지의 수행 시간이 필요하면서 컴퓨터 내에 있는 메모리와 같은 자원을 덜 사용하는 알고리즘이다.

 

 



 

 

수행 시간 측정 방법

 

주로 clock 함수가 이용된다.

clock 함수는 호출 프로세스에 의하여 사용된 CPU 시간을 계산한다.

 

 

clock_t clock(void);

 

clock 함수는 호출되었을 때의 시스템 시각을 CLOCKS_PER_SEC 단위로 반환한다.

알고리즘을 시작하기 전에 한번 clock 함수를 호출하여 start 변수에 기록하고, 알고리즘이 끝나면 다시 clock 함수를 호출하여 finish 변수에 기록한 다음, 초단위의 시간을 측정하기 위하여 (finish - start)값을 CLOCKS_PER_SEC으로 나누어 주면 된다.

 

 

 

 

 

 

 

'프로그래밍 > 자료구조' 카테고리의 다른 글

[STL] 시퀀스 컨테이너 , 연관 컨테이너  (0) 2015.04.28

[Unity3D] Missing adactivity with android.configchanges in androidmanifest.xml

광고를 붙이고 디바이스에서 돌렸더니 이런 Error가 아래와 같이 나타났습니다.


missing adactivity with android.configchanges in androidmanifest.xml



구글링 해본결과, Androidmanifest.xml에 Android Activities, meta-data tag를 제대로 추가안한게 문제였습니다.




 <!-- Denote the referenced Google Play services version -->

<meta-data android:name="com.google.android.gms.version"

        android:value="@integer/google_play_services_version" />





 <!-- Google Mobile Ads Activity -->

 <activity android:name="com.google.android.gms.ads.AdActivity"

              android:label="@string/app_name"

              android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">

      </activity>




해결방법은 Androidmanifest.xml에 위의 내용을 다시 추가하면 됩니다.

[게임/PS3]퍼피티어(Puppeteer)

2014년 7월  PlayStation Plus 게임으로 '퍼피티어'라고 귀여운 목각 인형이 그림그려져 있고, 한글판이길래 체험판을 했었는데, 하는 내내 우아~ 감탄사 연발했습니다. 연출이 너무 멋있었거든요. 2인용 게임도 가능해서 바로 Plus가입해서 즐겼습니다. 이 글은 아마 게임 연출에 대한 찬사로 도배될 것 같아요.


 

 '퍼피티어'는 2013년 9월에 발매되었고, 횡스크롤 액션 시스템으로 되어있습니다. 

 '쿠타로' 라고 불리는 인형이 자기 몸만큼이나 커다란 가위로  나쁜놈들, 주변 사물에 가위질을 합니다. 이를테면 나뭇잎, 밧줄을 자르면서 이동을 합니다. 그리고, 게임을 진행하면서 다양한 '헤드'를 얻을 수 있습니다. 

 '쿠타로'는 오프닝에서 나쁜놈 '문베어킹'에게 머리를 먹힙니다. 그래서 머리가 없습니다. 그래서 플레이하면서 얻게 되는 '헤드'를 머리에 꽂고 돌아댕깁니다.'헤드'는 약 100개 정도가 있으며, 헤드마다  액션이 있습니다. 스테이지 중간중간 하얗게 헤드모양의 이미지가 깜빡깜빡 표시되는곳이 있는데, 그 곳에서 헤드 액션을 하면 숨겨진 보너스 스테이지로 이동하기도 하고, 보스전에서 도움이 되는 것들을 줍니다. '헤드'는 쿠타로가 공격을 당하면 떨구고, 시간내에 줍지 않으면 없어집니다.  그렇게 머리를 모두 잃어버리면 게임 오버가 됩니다.


 스토리는 인형극으로 꾸며 진행합니다. 유저가 인형극을 바라보는 관객이 되고 , 무대에서는 인형들이 연기를 하는 연기자가 됩니다. 종종 관객의 웃음소리가 나오기도 해서 인형극을 보고 있다는 느낌을 한층 더해줍니다.  무대를 꾸미는 오브젝트들의 구성이나 극을 바라보는 구도가 참 다양합니다. 이 게임에 제일 마음에 드는 부분입니다.

 화면에는 무대를 꾸미듯 오브젝트들이 순식간에 추가됩니다. 이때 오브젝트들이 사방에서 튀어나와 살짝씩 튕기는 느낌을 연출합니다. 표현력이 부족해서 이해하기 어렵지만 동영상을 보면 알 수 있습니다. 


그리고 캐릭터들의 애니메이션들이 재밌고, 무척이나 다양합니다. 공포 게임 사이렌의 애니메이터였던 개빈 무어가 제작에 참여했다고 합니다.  용감한 기사로 보여지는 캐릭터인데, 커다란 보스를 코앞에서 직면하니  까 무서워서 다리를 달달 떠는것도 아주 귀여웠습니다.ㅎㅎㅎ 어떤 캐릭터의 행동을 보느라 다른 캐릭터의 애니메이션을 놓치기도하는데, 놓친 애니메이션을 보기 위해서 다시 한 번 플레이해서 보고 싶기도합니다. 


아래 동영상은 프로모션 영상입니다.




 게임 플레이는 생각했던 것보다 호흡이 빠릅니다. 순식간에 후루룩 빠르게 지나가서 먹을것들도 먹지 못하는 상황이 자주 발생합니다. 먹지 못하는 것 정도는 지나쳐도 괜찮다고 생각하는데, 문제는 이겁니다. 플레이 중에 아래 자막으로 내레이션이라던지 캐릭터들 간의 대화가 나오는데, 정신없이 컨트롤 하느라 대사를 잘 보지 못합니다. 별로 중요한 대사를 치고 있지는 않은것 같지만, 플레이하다보니 스스로 대사를 놓친다는 생각이 드니 좀 씁쓸하기도 합니다. 지금도 2P로 즐기고 있는데, 1p로 한다면 무척이나 어려울 것 같습니다.

 이것저것 살펴보는 도중에 개빈 무어의 인터뷰를 보니 이런 말을 했습니다. '아들에게 어떤 형식의 게임을 플레이하고 싶냐고 물으니 5~10분 간격으로 짧게 짧게 많은 것이 바뀌는 게임을 플레이하고 싶다고 이야기했습니다. 그 대답을 듣고 빠르게 진행되는 게임을 만들어보고자 했습니다.' 아들의 바람대로 후다닥 진행되는가 봅니다.


목각인형이라는 독특한 소재에 게임플레이도 괜찮고, 연출부분은 요근래 본 게임 중에 제일 인상깊었습니다. 꽤 수작인데 인기는 그리 없어서 안타깝습니다. 인형극 무대 연출을 한번 보세요. 괜찮다고 느끼실겁니다.


[Unity3D] zipalign.exe가 없다는 빌드 에러.

*****로 표시한 이유는 각자 설치해둔 안드로이드 SDK경로 또는 개발중인 유니티 프로젝트의 경로이므로 생략했습니다.


바로 아래와 같은 오류가 나타났습니다.



Error building Player: Win32Exception: ApplicationName='******sdk경로/sdk\tools\zipalign.exe', CommandLine='4 "******\Temp/StagingArea/Package_unaligned.apk" "

******\Temp/StagingArea/Package.apk"', CurrentDirectory='Temp/StagingArea'



구글링을 해본결과 안드로이드 SDK가 설치되어있는 tools 폴더에  zipalign.exe파일이 없기 때문에 오류를 내는것으로 확인했습니다.


해결방법은 

안드로이드 SDK가 설치되어있는 경로\sdk\build-tools\andorid -4.4W 폴더에 있는 파일들을 복사하여

안드로이드 SDK가 설치되어있는 경로\sdk\tools에 붙여넣습니다.



[Unity3D] Google Play Store APK 릴리즈 모드

구글 플레이 스토어 APK 릴리즈 모드





구글 플레이 스토어에 APK를 업로드시 릴리즈 모드로 올리라는 표시가 될 때가 있는데,

릴리즈 모드에는 개발자의 서명인 Keystore 파일이 있어야합니다.


같은 프로젝트라면 한 번 적은 서명은 계속 쭉 똑같이 사용해야합니다. 

같은 프로젝트이지만 서명이 다르다면 업로드가 되지 않습니다.



1. File/Build Settings/Publishing Settings or 

Edit/Project Settings/Player/Publishing Settings를 열어보면 Keystore, Key를 Inspector창에서 확인할 수 있습니다.


2. 처음 생성시에는 Create New Keystore를 체크하며, 이 다음부터는 Use Existing Keystore를 선택하고 이전에 입력한 Password를 입력하여 진행하면됩니다.


3. Browse Keystore버튼을 눌러서 keystore파일을 저장할 이름위치를 지정합니다.


4. Keystore password, Confirm password를 적어도 6글자이상 입력해야합니다. 이둘이 불일치할 경우 다음으로 진행하지 못하므로 잘입력해주세요.


5. Key에 Alias Unsigned(debug) 콤보박스를 클릭하여 Create a new Key를 선택합니다.



6. Create a new Key를 선택하면 아래와 같은 창이 뜨게됩니다.



7. Alias, Password, Confirm, Validity(years) 이 4가지만 입력을 하고, 이외의 정보는 입력하지 않아도 Key가 생성이 됩니다.


Alias는 원하는 Key 이름Validity(years)는 이 Keystore의 유효기간입니다. 기간이 짧을 경우 앱 등록시 경고가 뜨게 됩니다. 기본 50년으로 설정되어있는데 그대로 놔두고 key를 생성합니다.

 

8. 입력이 완료되었으면, Alias 콤보박스로 입력한 key를 선택하고, password를 적습니다.


맨아래 Split Application Binary 체크박스가 있는데, 이것은 keystore와는 상관 없이 .obb파일을 생성하는지에 대한것이므로, 체크안하셔도 됩니다.



이대로 Build를 하면 릴리즈 모드가 완성됩니다.






[Java] 접근 제어자(access modifier) - public, protected, ( default ), private

접근 제어자(access modifier)

 

 


 

 

멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.

 

접근 제어자가 지정되어 있지 않다면, 접근 제어자가 default이다.

default임을 알리기 위해 실제로 default를 붙이지 않는다.

 

접근 제어자가 사용될수 있는 곳은 클래스, 멤버변수, 메서드, 생성자 입니다.

 

 private  같은 클래스 내에서만 접근 가능하다.
 default  같은 패키지 내에서만 접근 가능하다. < -- 비추합니다.
 protected  같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
 public  접근 제한이 전혀 없다.

 

 

 대상 사용가능한 접근 제어자 
 클래스   public, (default)
 메서드   public, protected, (default), private
 멤버변수
 지역변수   없음

 

 

 

 


 

 

접근 제어자를 이용한 캡슐화

 

접근 제어자를 사용하는 이유는 무엇인가!?

클래스의 내부에 선언된 데이터를 보호하기 위해서 입니다.

 

비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터의 접근을 제한하는 것이 필요하다.

이것을 데이터 감추기(data hiding)이라고 하며, 객체지향개념의 캡슐화(encapsulation)에 해당하는 내용이다.

 

또 다른 이유는 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버변수나 부분작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위해서이다.

외부에서 접근할 필요가 없는 멤버들을 private으로 지정하여 외부에 노출시키지 않음으로써 복잡성을 줄일 수 있다.

 

1. 외부로부터 데이터를 보호하기 위해

2. 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해

 

 

 


public class Test
{
    public static void main(String[] args) 
    {
        Time t = new Time(12, 35, 30);
        System.out.println(t);
        t.setHour(t.getHour() +1);
        System.out.println(t);
    }    
}

class Time
{
    private int hour;
    private int minute;
    private int second;
    
    Time(int hour, int minute, int second)
    {
        setHour(hour);
        setMinute(minute);
        setSecond(second);
    }
    
    public int getHour(){ return hour;}
    public void setHour(int hour)
    {
        if (hour < 0 || hour > 23) return ;    // 0~23의 값을 갖는 hour
        this.hour = hour;
    }
    public int getMinute(){ return minute;}
    public void setMinute(int minute){
        if(minute <0 || minute >59) return; // 0~59의 값을 갖는 minute
        this.minute = minute;
    }
    public int getSecond(){ return second;}
    public void setSecond(int second){
        if(second <0 || second > 59) return; // 0~59의 값을 갖는 second
        this.second = second;
    }
    
    public String toString()    //이건 오버라이딩인가?? 음.. ㅎ
    {
        return hour + ":" + minute +":" + second;
    }
}



 

 

 

* 아래 내용은 많이 중요합니다.

 

생성자 접근 제어자

 

생성자에 접근 제어자를 사용한다면 인스턴스의 생성 제한 할 수 있다.

 

생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다. 그래도 클래스 내부에서는 인스턴스의 생성이 가능하다.

 

 

 


class Singleton
{
    private static Singleton s = new Singleton();    //getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
    private Singleton()
    {
    }
    
    //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다.
    public static Singleton getInstance()
    {
        return s;
    }
}

 

이렇게 생성자를 통해 직접 인스턴스를 생성하지 못하게 하고, public 메서드를 통해 인스턴스에 접근하게 함으로써 사용할 수 있는 인스턴스의 개수를 제한할 수 있다.

 

생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.

 

 

자손 클래스의 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야만 하는데, 생성자의 접근 제어자가 private이므로 자손클래스에서 호출하는 것이 불가능 하기 때문이다.

 

 

Tip.

그래서 클래스 앞에 final을 더 추가하여 상속할 수 없는 클래스라는것을 알리는 것이 좋다.

 

 

Math클래스는 몇 개의 상수와 static메서드만으로 구성되어 있기 때문에 인스턴스를 생성할 필요가 없다. 그래서 외부로부터의 불필요한 접근을 막기 위해 다음과 같이 생성자의 접근 제어자를 private으로 지정한다.

 


public final class Math{
         private Math(){}
}

 


public class Test
{
    public static void main(String[] args) 
    {
//        Singleton s = new Singleton();    //Singleton()은 private이므로 접근할 수 없어요.
        Singleton s = Singleton.getInstance();
    }    
}

class Singleton
{
    private static Singleton s = new Singleton();    //getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
    private Singleton()
    {
    }
    
    //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다.
    public static Singleton getInstance()
    {
        if(s == null)
        {
            s = new Singleton();
        }    return s;
    }
}

 

 

 

 

 

정리.

 대상 사용가능한 제어자 
 클래스 public, (default), final, abstract 
 메서드  모든 접근 제어자, final, abstract, static
 멤버변수  모든 접근 제어자, final, static
 지역변수  final


 

주의사항

 

 1. 메서드에 static과 abstract를 함께 사용할 수 없다.
 static메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

 

 2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고,
 abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순이 된다.

 

 

 

 

 

 

 

 

 

 

 

 3. abstract메서드의 접근 제어자가 private일 수 없다.
 abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면,
 자손클래스에서 접근 할 수 없기 때문이다.

 

 

 

 

 

 4. 메서드에 private과 final을 같이 사용할 필요는 없다.
 접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 주 하나만 사용해도 의미가 충분하다.

 

 


 

참고 서적

Java의 정석

http://book.naver.com/bookdb/book_detail.nhn?bid=4473030

[Java] 제어자 (modifier)에 대한 이야기

제어자 (modifier)




클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.

제어자의 종류는 크게 접근 제어자와 그 외의 제어자로 나눌 수 있다.

 

 접근 제어자

 public, protected, default, private

 그외

 static, final, abstract, native, transient, synchronized, volatile, strict

 

 

제어자는 클래스나 멤버변수와 메서드에 주로 사용 된다.

단, 접근 제어자는 네 가지 중 하나만 선택해서 사용할 수 있다.

 

참고.

제어자들 간의 순서는 관계없지만 주로 접근 제어자를 제일 왼쪽에 놓는 경향이 있다.

 



 

1. static ? - 클래스의, 공통적인

 

static은 인스턴스와 상관 없다. '클래스의' 또는 '공통적인' 이라는 의미를 가지고 있다. 인스턴스 변수는 하나의 변수를 모든 인스턴스가 공유하기 때문이다.

 

인스턴스메서드와 static메서드의 근본적인 차이는 메서드 내에서 인스턴스 멤버를 사용하는가의 여부에 있다.

 

static이 사용될 수 있는 곳은 멤버변수, 메서드, 초기화 블럭 입니다.

 

 제어자

대상 

의미 

 

Static 

멤버변수 

 - 클래스 변수는 인스턴스를 생성하지 않고도 사용 가능하다.

 - 클래스가 메모리에 로드될 때 생성한다.

 메서드

 - 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.

 - static 메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다

 



 

참고.

static초기화 블럭은 클래스가 메모리에 로드될 때 단 한번만 수행되며, 주로 클래스변수(static 멤버변수)를 초기화하는데 주로 사용된다.

 



 

2. final  - 상수 개념, 마지막의, 변경될 수 없는



final 타입 변수 = 값 ;   ----> 값을 변경 할 수 없다.

final 타입 변수()         ----> 오버라이딩 못함.

 

클래스에 사용되면 자신을 확장하는 자손 클래스를 정의하지 못하게 된다.


final이 사용될 수 있는 곳은 클래스, 메서드, 멤버변수, 지역변수 입니다.

 

 제어자

대상 

 의미

 final

 클래스

   변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.

   그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.

 메서드

    변경될 수 없는 메서드

   final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.

 멤버변수

    변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다.

 지역변수

참고. 대표적인 final 클래스로는 String과 Math가 있다.

 

 

생성자를 이용한 final 멤버변수 초기화

 

final이 붙은 변수는 상수이므로 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스변수의 경우 생성자에서 초기화 되도록 할 수 있다.

 

클래스 내에 매개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 멤버변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다.

 

 


public class Test{
    public static void main(String[] args) 
    {
        Card c = new Card("HEART", 10);
        System.out.println(c.KIND);
        System.out.println(c.NUMBER);
    }    
}
class Card
{
    final int NUMBER;    // 상수지만 선언과 함께 초기화 하지 않고
    final String KIND;        // 생성자에서 단 한번만 초기화할 수 있다.
    static int width = 100;
    static int height = 250;
    
    Card(String kind, int num)
    {
        KIND = kind;        //매개변수로 넘겨 받은 값으로 KIND와 NUMBER를 초기화한다.
        NUMBER = num;    
    }
    
    Card()
    {
        this("HEART",1);
    }
    
    public String toString()
    {
        return ""+ KIND +" "+NUMBER;
    }

}

 

 



 

3. abstract - 추상의, 미완성의

 

abstract는 ' 미완성 '의 의미를 가지고 있다.

메서드의 선언부만 작성하고, 실제 수행내용은 구현하지 않은 추상메서드를 선언하는데 사용된다.

 

abstract가 사용될 수 있는 곳은  클래스, 메서드 입니다.

 

 제어자

대상

의미 

 abstract

클래스

 클래스 내에 추상메서드가 선언되어 있음을 의미한다. 

 메서드

 선언부만 작성하고 구현부는 작성하지 않은 추상메서드임을 알린다.

 

참고.

추상메서드가 없는 클래스도 abstract를 붙여서 추상클래스로 선언하는 것이 가능하기는 하지만 그렇게 할 이유는 없다.





참고 서적

Java의 정석

http://book.naver.com/bookdb/book_detail.nhn?bid=4473030