'게임개발공부/C++'에 해당되는 글 4건

  1. 2014.07.08 const_cast의 난점.
  2. 2014.06.27 OOP객체지향 프로그래밍 1) 5대 원칙 1
  3. 2014.06.26 OOP객체지향 프로그래밍 1) 4가지 특징
  4. 2014.06.25 C++ 과 C의 차이점 2

다음의 코드를 보자



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
 
int main (void)
{
 
 const int b = 100;
 
 printf("%d\n", b);
 
 int* temp = const_cast<int*>(&b);
 
 *temp = 200;
 
 int* temp2 = temp;
 
 printf("%d\n", b);
 printf("%d\n", *temp);
 printf("%d\n", *temp2);
 
 int* temp3 = const_cast<int*>(&b);
 
 printf("%d\n", *temp3);
 
    return 0;
 
}

const_cast는 참조형의 const나 휘발성을 제거해주는 캐스트방식이다. 즉 위의 const int b는 값형이므로 언뜻보면 캐스트가 안될 수 있지만.
실제 출력되는 값은 temp2의 값이 200으로 변환되어서 컴파일까지 잘 된다.
이게 왜 되는 것인가? const int b의 값을 바꾸는게 되는것인가?
이유는 컴파일러에 있다고 본다. const int b라고 되어있는 부분은 컴파일 시점에서 const int b가 되는 것이 아니라. 100으로 치환되기 때문에 값의 변경과 상관 없이 100의 상수값으로 변경된 것이고 그렇기 때문에 후에 변경하는 값은 b의 값을 아무리 출력해도 100이라는 상수값으로 대체되었기 때문에 100으로 출력되는 것으로 보인다.


Posted by JJOREG

인터넷에 좋은 글들이 있지만 저는 제 방식대로 게임만들때에 대비해서 생각하는 편이라 정리해서 올립니다.

일단 이런 규칙들이 생긴 이유에 대해서는 처음에는 몰랐지만 지금은 아주 통감하고 있습니다. 특히 팀프로젝트 할때는 더더욱 그렇습니다.


아래는 http://b-jay.tistory.com/115사이트에서 가져온 도입 이유입니다.


1.     경직성

- 무엇이든 하나를 바꿀 때마다 반드시 다른 것도 바꿔야 하며, 그러고 나면 또 다른 것도 바꿔야 하는 변화의 사슬이 끊이지 않기 때문에 시스템을 변경하기 힘들다.

나 : 팀원에서 묻습니다. 이것좀 바꿔줄 수 있어? 

팀원A : 그걸 바꾸면 구조를 싸그리 고쳐야 해요. 안됨.

나 : 아니 어떻게 짰으면 그거 하나 바꿨다고 구조를 다 바꿔?

팀원A : 이미 그렇게 만들었어요 시간 더든다니까요...

나 : 그래 그럼 뭐 어쩔 수 없지...(아니 무슨 프레임워크의 최상위 클래스에 순수가상함수를 넣자는 것도 아니고 뭐만하면 )

2.     부서지기 쉬움

- 시스템에서 한 부분을 변경하면 그것과 전혀 상관없는 다른 부분이 작동을 멈춘다.

팀원B : 형 제가 이 코드에 이거 바꿨는데 형께 작동 안하는데요.

나 : 응 왜?

팀원B : 그 클레스를 만든게 형이라.

나 : (훑어보고)어 미안 이거 이러저러해서 동작이안되네... 고칠께... (아... 내가 왜 이걸 이렇게 짰지?)

3.     부동성

- 시스템을 여러 컴포넌트로 분해해서 다른 시스템에 재사용하기 힘들다.

나 : 이거 기능 빼서 이 클래스로 다시 만들께.

팀원들 : 안되요 그거 바꾸면 구조다 망가짐.

나 : 아니... 그러니까... 왜...

4.     끈끈함(점착성)

- 개발 환경이 배관용 테이프나 풀로 붙인 것처럼 꽉 달라붙은 상태다. 편집 - 컴파일 - 테스트 순환을 한 번 도는 시간이 엄청나게 길다.

나 : 아 이 클래스 너무 헤더가 많은데... 컴파일!

나 : (10분동안 기다리다가 돌아와서) 아직도! 안끝났어!!!!

5.     쓸데없이 복잡함

- 괜히 머리를 굴려서 짠 코드 구조가 굉장히 많다. 이것들은 대개 지금 당장 하나도 필요 없지만 언젠가는 굉장히 유용할지도 모른다고 기대하며 만들었다.

나 : 이걸 이렇게 이렇게 짜면... 애들이 이러이러 써줄꺼야...

2개월후

나 : 아무도 사용하지 않았군 괜히 만든 기능이네...

6.     필요 없는 반복    

- 코드를 작성한 프로그래머 이름이 마치 ‘복사’와 ‘붙여넣기’ 같다.

나 : 아니 함수객체나 static 클래스로 함수화 시키면 되지 왤케 같은 함수가 많아.

나 : 전에 형이 만든 기능도 한번밖에 안쓰던데요. 그럴줄 알았죠.

7.     불투명함

- 코드를 만든 의도에 대한 설명을 볼 때 그 설명에 ‘표현이 꼬인다’라는 말이 잘 어울린다.

나 : 이건 이러저러해서 이러저러하기 때문에 이러저러한 기능을 담당하는 클래스야...

모두들 : 어려워...


예제코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// TEST.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class 존재
{
private:
    int 세상속의X축위치;
    int 세상속의Y축위치;
    int 세상속의Z축위치;
 
public:
    virtual void 그려지다() { cout << "나 그려진다!" << endl; }
    virtual void 타입을말해봐() { cout << "객체다!" << endl; }
};
 
class 생물 : public 존재
{
private:
    TCHAR* 생물의이름;
    int 공격력;
    int 방어력;
    int 수명;
 
public:
    virtual void 이동() = 0;
    virtual void 사망() = 0;
    void 넌뭐니?() { cout << "난 생물이다!!!!!!" << endl; }
};
 
class 괴물 : public 생물
{
private:
    int 생명력;
 
public:
    virtual void 이동() { cout << "괴물 이동한다." << endl; }
    virtual void 사망() { cout << "괴물 죽는다." << endl; }
    void 포효하다(void);
    void 공격하다(const int 데미지);
};
 
class 사람 : public 생물
{
private:
    int 공격력;
    int 방어력;
 
public:
    virtual void 이동() { cout << "사람 이동한다." << endl; }
    virtual void 사망() { cout << "사람 죽는다." << endl; }
    virtual void 그려지다() { cout << "사람은 다르게 그려진다" << endl; }
    void 말하다(void);
    void 먹다(void);
    void 공격하다(void) { cout << "사람 이동한다." << endl; }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    사람 철수;
 
    철수.타입을말해봐();
    철수.그려지다();
    철수.넌뭐니();
    철수.이동();
    철수.사망();
 
    cout << endl;
 
    생물* 고질라 = new 괴물;
    고질라->이동();
    생물* 울트라맨 = new 사람;
    울트라맨->이동();
 
    return 0;
}


1.      SRP (단일 책임 원칙)


Single Responsibility Principle

모든 클래스는 단 하나의 책임을 가져야 한다는 것이다. 만들 때나 수정할 때 한가지 이상의 이유가 있어서는 안된다.


클래스를 만들다보면 하나의 클래스에서 너무 많은 역할을 담당할 때가 있다. 특히 게임 오브젝트에 대한 내용이 그렇다.

게임 오브젝트는 상호작용, 렌더링, 게임내데이터등 많은 역할을 맡을 때가 많습니다.

또한 그것들이 또 다시 상호작용한다. 

그래서 캐릭터의 렌더링이 이상할때도 게임오브젝트를 보고 충돌이 이상할때도 게임오브젝트를 보게되는 경우가 많습니다.

즉 하나의 클래스에 너무 많은 부담이 가해지는 것이다.

물론 캐릭터에 이상이있다... 라는 점에서는 그것을 담당하는 게임 오브젝트 클래스를 보는게 맞지만. 

캐릭터의 렌더링, 캐릭터의 상호작용 등으로 들어가기 시작하면 또다시 복잡해 지기 시작한다.

이럴때는 각 기능들을 다형성을 이용해서 또 다시 클레스로 세분화시키는 작업을 하게된다.


나와 같은 경우에는 게임의 리소스를 관리하는 리소스관리자 클래스를 만들고 또 그 아래 세부적으로 텍스처를 관리하는 텍스처매니저 클래스, 매쉬를 관리하는 매쉬매니저 클래스를 따로 놓거나 아니면 두가지를 애초부터 분리해 놓기도한다.

즉 텍스처 로딩이 이상한데? 라고 하면 텍스처매니저 클래스를 보면 되고 매쉬가 이상하다! 그렇다면 매쉬매니저 클래스를 보면 된다.


2.      OCP (개방-폐쇄 원칙)


Open Closed Principle
모든 소프트웨어 구성 요소는 확장에 대해서는 개방되어있지만, 수정에 대해서는 폐쇄되어있다는 원칙이다.


이미 만들어진 클래스를 수정하는 것은 항상 문제가 따른다. 이를 잘 지키기 위해서 위해서 가상함수를 잘 이용해야 한다.
생물 클래스는 이동과 사망을 가지고 있다. 생물들은 마땅히 이동할수 있다고 생각했고 공통되는 기능은 상위 클래스에 정의되어 있거나 혹은 순수가상함수로 꼭 구현해야될 기능으로 정의되어 있다.
즉 생물 클래스는 생물클래스를 통해서 사람이나 괴물 같은 하위 클래스를 확장하는데에는 개방되어 있지만.
반대로 생물 클래스의 이동이나 사망을 수정하거나 할 이유는 없으므로 수정에 대해서는 폐쇠되어 있다.

3.      LSP (리스코프 치환 원칙)


Liskov Substitusion Principle

자식 클래스는 언제나 자신의 부모 클래스로 교체될수 있다는 원칙이다.


부모클래스의 자리에 자식클래스가 들어가더라도 잘 작동해야 한다는 것이다.

즉 생물 클래스의 자리에 자식 클래스인 괴물이나 사람이 들어가도 잘 작동해야하고 실제대로 잘 작동한다.

이는 상속의 본질을 의미한다. 이에대해서는 잘 작동 못하게 짜는 것도 굉장히 힘이들지만 기능이 많아지다보면 규칙은 내다버리고 싶은 경우가 다수입니다.

즉 부모의 인터페이스를 자식은 모두 만족할 수 있도록 구현해야 합니다. c++이라면 어떤 부모 클래스형의 포인터가 있을때 그 포인터 형으로 자식 클래스를 넣어 놓습니다.

그 상태에서 어떤 자식 클래스를 넣었을 때는 잘 작동하고 어떤 녀석을 넣었을 때는 작동하지 않는다면 그것은 그 자체로 후일 문제를 일으킬 가능성이 존재합니다.

  • LSP는 상속(Inheritance), 다형성(Polymorphism) 과 관련된 원칙.
상속은 코드 재사용 이라는 이유로 과용 될수 있는 기능. 과잉 사용된 상속은 복잡한 계층구조와 커플링을 타이트하게 함으로써 객체지향으로 얻기 위한 유지관리 비용 감소에 악영향을 미치는 요소 중 하나.

라는 의견이 있으니 참고해 주시기 바랍니다.


4.      DIP (의존 관계 역전 원칙)


Dependency Inversion Principle
고차원의 모듈은 저차원의 모듈에 의존하면 안된다. 이 두 모듈 모두 추상적인 것에 의존해야 한다.
추상화된것은 반대로 구체적인 것에 의존해서는 안된다. 구체적인 것이 추상적인 것에 의존해야 한다.
상위 클래스는 하위 클래스에 의존해서는 안된다는 법칙이다.


고차원의 클래스는 자신의 하위객체에 어떤것도 의존해서는 안됩니다. DLL을 사용할때 이런일이 많이 발생합니다. DLL을 만들어 놓고 클라이언트에 있는 어떤 객체가 필요하다던가 하는 일이 있는데.

애초에 잘못 짠 것입니다. 추상클래스는 하위의 구현될 가능성이 있는클래스에 의존해서는 안됩니다. 

순수가상함수가 있는 클래스는 다른 클래스에 의존해서 작동해서는 안된다는 것입니다.

이는 위의 코드에서도 잘 나와있습니다.

고질라와 울트라맨을 만들어 낼때 둘은 모두 생물이라는 클래스의 포인터 타입으로 동적할당 되었습니다.

여기에서 예를 들자면 꼭 사람으로 할당되어야 하거나 꼭 울트라맨으로 할당되어야 하는 일이 벌어진다면 그것만으로도 객체지향을 해치는 결과가 될 수 있습니다.

또한 이러한 점에 있어서는 함수인자등으로 받을때 하나의 클래스로 대부분이 통용되므로 


5.      ISP (인터페이스 분리 원칙)


Interface Segregation Principle

클라이언트에서 사용하지 않는 메서드는 사용해선 안된다. 


이건 한가지 예를 들어보면 편할 것입니다.

만약 생물 클래스 아래에 사망과 죽음 말고 갑자기 말하다라는 함수가 생성되었습니다. 

하지만 괴물은 말하다에 아무것도 할일이 없습니다. 하지만 추상클래스가 어쩔수 없이 구현만 해놓고 안에는 아무것도 넣어놓지 않았습니다.

하지만 이것을 말그대로 어쩔 수 없이 구현한 것입니다.

그런 어쩔수 없는 구현을 하위 클래스로 내려서 어쩔수 없지 않게 만드는 것. 메소드가 필요 없음에도 다른 기능들 때문에 상위의 클래스를 상속받지 않게 상속구조를 정리하거나

메소드를 분리하는 것이 바로 인터페이스 분리 원칙의 핵심입니다.

'게임개발공부 > C++' 카테고리의 다른 글

const_cast의 난점.  (0) 2014.07.08
OOP객체지향 프로그래밍 1) 4가지 특징  (0) 2014.06.26
C++ 과 C의 차이점  (2) 2014.06.25
Posted by JJOREG

심플하게 말해서 객체지향 프로그래밍은 프로그래밍을 전체의 흐름으로 보지 않고 객체를 기반으로 해서 구현하는 것입니다.

객체지향 프로그래밍에는 4개의 특징과 5가지 원칙이 있습니다 그것에 대해서 예제 코드와함께 설명하겠습니다.


예제코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// TEST.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
 
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
class 존재
{
private:
    int 세상속의X축위치;
    int 세상속의Y축위치;
    int 세상속의Z축위치;
 
public:
    virtual void 그려지다() { cout << "나 그려진다!" << endl; }
    virtual void 타입을말해봐() { cout << "객체다!" << endl; }
};
 
class 생물 : public 존재
{
private:
    TCHAR* 생물의이름;
    int 공격력;
    int 방어력;
    int 수명;
 
public:
    virtual void 이동() = 0;
    virtual void 사망() = 0;
    void 넌뭐니?() { cout << "난 생물이다!!!!!!" << endl; }
};
 
class 괴물 : public 생물
{
private:
    int 생명력;
 
public:
    virtual void 이동() { cout << "괴물 이동한다." << endl; }
    virtual void 사망() { cout << "괴물 죽는다." << endl; }
    void 포효하다(void);
    void 공격하다(const int 데미지);
};
 
class 사람 : public 생물
{
private:
    int 공격력;
    int 방어력;
 
public:
    virtual void 이동() { cout << "사람 이동한다." << endl; }
    virtual void 사망() { cout << "사람 죽는다." << endl; }
    virtual void 그려지다() { cout << "사람은 다르게 그려진다" << endl; }
    void 말하다(void);
    void 먹다(void);
    void 공격하다(void) { cout << "사람 이동한다." << endl; }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    사람 철수;
 
    철수.타입을말해봐();
    철수.그려지다();
    철수.넌뭐니();
    철수.이동();
    철수.사망();
 
    cout << endl;
 
    생물* 고질라 = new 괴물;
    고질라->이동();
    생물* 울트라맨 = new 사람;
    울트라맨->이동();
 
    return 0;
}


4가지 특징


1. 추상화 

프로그램의 구조를 구조와 단계로 생각하기 전에 추상화 시켜서 생각 할 수가 있다. 이는 상속과도 밀접한 개념으로 객체들이 가진 공통적인 데이터등을 뽑아내는 작업입니다.

당연히 예를 들면 더욱더 편할 것입니다.

먼저 존재라는 클래스를 정의하고 그 존재의 상속을 받는 생물이라는 클래스를 만들고 또 그를 상속받는 괴물이라는 클래스를 만들었습니다.

즉 말그대로 클래스를 정의함에 있어서 공통되는 데이터를 뽑아내며 기능으로서의 클래스가 아니라 현실과 대비하여 추상적으로 프로그래밍을 할 수 있게 되는 특징이 됩니다.


1. 캐릭터를 만든다? 

2. 고민하지 않고 캐릭터 클래스를 만든다. 

3. 어 근데 몬스터와 플레이어가 모두 같은 걸 쓰네? 

4. 공통적인 변수를 빼내어 그 상위 클래스인 생물 클래스를 만든다.


2. 캡슐화

괴물 클래스를 보겠습니다. 생명력과 공격력은 private: 키워드로 묶여있습니다. 저 키워드는 클래스를 만들어도 외부에서 내부의 맴버를 사용할 수 없게 만드는 것입니다.

즉 괴물의 private 맴버인 생명력과 공격력을 직접 바꿀 수는 없습니다.

하지만 바깥으로 들어나야 몬스터를 죽이던가 살리던가 혹은 몬스터가 공격하거나 방어하는 상호작용이 이루어 질 것입니다.

그것을 내부의 함수를 통해서 외부에서 이용하게 합니다. 공격한다! 라는 기능자체를 만들어 내는 것이지요. 

즉 내부의 데이터 값을 기반으로해서 클래스 내부에 있는 기능만을 바깥으로 내보이는 것입니다.


1. 몬스터는 생명력이 있어. 

2. 외부에서 맘대로 수정하지 못해!

3. 외부에 공개된 실행할수 있는 맞는다는 기능 공격한다는 기능만을 외부에 공개할께 너희들은 내가 공개한 것만 사용해.

 

* 보너스 부록

여기에 +하여 정보은닉이라는 특징이 있는데이는 캡슐화와 거의 비슷한 의미를 가진다.

API를 사용하려는 사용자에서 필요 이상의 데이터나 잘못된 사용을 금지하고 사용자에게 필요한 정보만을 공개하며 나머지를 은닉하는 것을 의미한다. 어찌 보면 캡슐화와 거의 같은 개념이며이 녀석을 분리 시킬경우 5대 특징으로 표시한다.


3. 상속성

존재 -> 생물 -> 괴물로 이어지는 상속라인을 보면 알겠지만 괴물은 존재와 생물이 가지고 있는 클래스 구조는 계층적으로 아래로 내려오며 상위의 함수나 맴버변수들을 모두 사용할 수 있습니다. 즉 새로운 기능을 재정의할 필요가 없어지는 것이죠.

예를 들기 위해서 실행 결과를 한번 보겠습니다.




철수는 자신의 상위 클래스의 기능들을 구현해서 사용하고 있습니다.

하지만 무리 없이 사용할 수 있죠. 더 나아가서 자신이 다르게 사용하고 싶은 함수는 자신이 다시 재정의 해서 사용합니다.

상속을 하게 되면 상속을 통해서 괴물이나 사람은 그려지다라는 기능에 대해서 굳이 자신에게 구현을 하지 않아도 부모 클래스의 기능으로 사용이 가능해집니다. 

코드의 재사용성을 높여주게 되며 상속을 통해서 클래스를 추상화시키는데에도 도움이 됩니다.


4. 다형성

마지막으로 울트라맨과 고질라는 같은 생물* 형입니다. 하지만 실행은 고질라는 괴물 이동한다. 울트라맨은 사람 이동한다. 라는 글을 출력합니다.

virtual키워드를 이용해서 구현한 함수는 동적 바인딩이라는 작업을 거칩니다. 

동적 바인딩을 먼저 이해하기 전에 동적할당을 먼저 이해하면 편합니다. 

tmain() 함수를 보면 마지막즈음 포인터를 이용해서 사람을 동적할당 하고 있습니다.

이때 포인터의 타입은 생물* 이지만 할당은 괴물* 사람*입니다. 즉 동적할당을 위해서 받아들인 타입과 상관없이 실제 할당받은 객체타입의 함수를 실행합니다. 

이 모든 과정은 프로그램의 런타임중에 일어나게 됩니다. 이것이 동적 바인딩 입니다. 

즉 하나의 타입으로 보이는 객체가 실제 기능의 실행에서는 각자 다르게 동작하게 되는 것입니다.


virtual 키워드를 설명하기 가장 좋은 특징입니다.


알게된점 1)

C++은 디폴트가 비가상함수이고,
자바는 디폴트가 가상함수이다!!! (Oh ho)

'게임개발공부 > C++' 카테고리의 다른 글

const_cast의 난점.  (0) 2014.07.08
OOP객체지향 프로그래밍 1) 5대 원칙  (1) 2014.06.27
C++ 과 C의 차이점  (2) 2014.06.25
Posted by JJOREG

개념적인 차이


1. 패러다임


C는 절차지향적 언어(Procedural). 

C++은 흔히 객체지향언어(Multi paradigm).


하지만 C++은 엄연히 말해서 멀티패러다임 언어이며 객체지향이건, 절차지향이건 구현이 가능하며 C의 확장팩이라고 생각하면 편합니다. 

(엄밀히 말하면 그렇지 않습니다. C++은 C의 문법처럼 사용할수 있을 뿐이지 이미 오랜시간 C도 확장을 해왔고 C++도 확장을 해왔습니다. 마치 C의 문법처럼 쓰지만... 내부 동작은 전혀 다를 수도 있습니다. 마치 C++배워 놓고 C는 쉽게 배울 수 있을 거라 생각하지만 깊이 들어가면 역시... 끝도 없습니다.)

마찬가지도 C에서도 객체지향적으로 구현을 할 수가 있지만 C++은 그를 구현하기 위한 수많은 문법적 기능이 마련되어 있고

객체지향 중심적이지만 얼마든지 C로 회귀하여 C처럼 프로그래밍을 할 수도 있고 함수 프로그래밍등 다양한 프로그래밍을 소화할 수 있습니다.

하지만 굳이 C로 객체지향적인 코딩을 해야하는가가 문제가 됩니다.

마찬가지로 C++을 말할 때 마치 객체지향프로그래밍 언어의 대명사인 것처럼 말하지만 C++은 멀티패러다임 언어이다.

만약 객체지향형식 언어라고 c++을 정의했다면 저는 절대로 friend같은 키워드는 절대로 만들지 않았을 겁니다.

또한 더욱 깊이 들어간다면 객체지향언어니 절차지향언어니 따지는 것도 소용없다고 봅니다. 

말씀드렸듯이 언어는 언어이고 엄연히 말하자면 객체지향이나 절차적언어 같은 것은 일반적으로 통용되는 개발방식에 대한 내용입니다. 

즉 언어 자체를 그런 단어로 단정짓기는 힘들다는 이야기 입니다.


2. 개발방식


C는 하향식 접근 방법[각주:1]

C++는 상향식 접근 방법[각주:2]


C는 절자척 언어이기 때문에 기본 요소간의 순차적 수행이 되도록 서로간의 연결이 중요하다 단계별 공식화(linked-together) 이후 세부 사항으로 나눠집니다.
하지만 C++은 시작부터 추상적인 개념을 통해서 구성을 한 후 그 다음 그것들을 조합하는 방식으로 만들어 집니다.
이는 클래스와 객체를 통한 프로그래밍이 C++ 에서 주를 이루면서 생겨난 특징입니다.

물론 C++도 하향식 접근방식으로 개발이 될 수도 있고 혹은 그때그때 다를 수도 있지만 기본적으로 C++을 배우게 되면 상향식 접근 방법을 먼저 접하게 될겁니다.

왜냐하면 그게 편하니까요. 당신이 창조주로 세상을 만들어 낼수 있다고 할때 세상 만물이 창조되는 물리법칙, 전자기력, 핵력, 중력, 자기력등을 먼저 만들겠 습니까. 

아니면 태양을 만들고 바람을 만들고 사람을 먼저 만들겠습니까. 물론 프로그래밍 실력이 나아질수록 원론과 근본에 손을 먼저 쓰겠지만 그보다는 우리에게 친숙한 추상적인 객체에서부터 C++ 프로그래밍을 시작하는 것이 일반적입니다.

또한 이점은 구조적 프로그래밍과 객체 지향 프로그래밍의 큰 차이라고 볼 수도 있습니다.


문법적인 차이


1. class


c++ 에서는 class 가 생겼다!

class라는 것은 C++에서 감초 같은 역할을 합니다.

항상 사람들은 c++을 하면서 class 기존 C에서 부터 존재하던 struct와의 차이를 물어보는데 이에 대해서 좀 이야기를 해야할것 같다.


부록이에용~ C++에서의 CLASS와 STRUCT, 그리고 C의 STRCUT에 대해서 설명해 보겠음다.


1. C++의 CLASS는 CLASS내의 함수를 가질 수 있다. STRCUT도 함수를 가질 수 있다. C의 STRCUT는 함수호출을 할수 있다.

2. C++의 CLASS는 CLASS 맴버가 기본적으로 private. STRCUT는 public. C의 STRCUT 접근 지정자 자체가 없다.

3. C++의 CLASS는 상속이 가능하다, STRCUT 또한 상속이 가능하다, C는 개념 자체가 없다.

4. C++의 CLASS는 템플릿 사용 가능, STRCUT 또한 가능, C는 개념 자체가 없다.


음 차이가 없다. 정말 없다... 딱하나 2번 항목을 제외하고 나는 차이를 못느껴봤다.

어느정도로 차이가 없냐고?

심지어 이런짓도 가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct 생물
{
 
};
 
class 휴먼 : public 생물
{
    int a;
 
public:
    휴먼()
    {
        a = 0;
    }
};
 
template<class T>
struct 로봇 : public 휴먼
{
 
};

구조체를 클래스가 상속받고 그것을 다시 템플릿을 사용하는 구조체가 다시 상속 받는다. 객체화 다 잘된다.

현재까지 내가 파악한 파악한걸로는... 음... 

1. 어떤 의견으로는 구조체는 값타입 클래스는 참조타입이라는데 C#의 클래스와 구조체의 차이이다. C++에서 그런가? 확인할 수 없었다.

2. 어던 의견으로는 구조체는 new 동작시 디폴트 생성자가 없다면 묵시적으로 생성되는 디폴트 생성자가 호출이 안된다는데... 역시 명확하지 않다. 아니 모든 기능이 똑같은데 구조체라고 다를까 하는 생각이 있다. 


2. 오버로딩을 지원하지 않는다.


C++에서는 같은 함수명은 같지만 함수파라미터는 다른 오버로딩을 지원하지 않는다.


3. C는 참조변수 혹은 레퍼런스변수를 지원하지 않는다..


레퍼런스는 C++에서 생겨난 개념이다. 마찬가지로 C에서는 지원하지않는다.

C만 전문적으로 보신분들이 본다면 포인터와 비슷한 개념이지만 실제 값처럼 취급되는것이 레퍼런스이다.

& 기호를 사용하며 다음과 같습니다.

int a = 10;

int &A = a; 이와 같이 변수만 받을수 있으며 실제 a의 값처럼 사용된다.


---------------------------------


1. 글을 쓰면서 알게된 점 1. C++ 에서는 배열이나 함수가 포인터로 변환되는 것을 Decay(부식: 그러니까 모든 정보를 온전히 갖지 못한다는 이야기)라고 한다.

2. 템플릿으로 이런짓이 가능하다 허허허.... 항상 배운다. 정말...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
template<typename T, size_t n>
void foo(T (&p)[n])
{
    int size = sizeof(p) / sizeof(p[0]);
}
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    int temp[] = {1, 3, 3};
 
    foo(temp);
 
    return 0;
}

3. 배열의 이름과 포인터는 비슷한 동작을 하지만 절대로 같지는 않다. 물론 알고 있는 내용이지만 명확하게 다시한번 확인했다.

  1. 어떤 의사를 결정하거나 어떤 일을 수행하는 과정의 개괄적인 측면에서 시작하여 점차 세분화해 가며 처리하는 방식. 상향식 접근 방식(bottom-up approach)과 대별된다. [본문으로]
  2. 작은 부분부터 개발하고 후에 그것을 조합하여 하나로 만드는 것을 의미한다. [본문으로]
Posted by JJOREG
이전버튼 1 이전버튼