map 과 unordered_map 의 검색 속도 비교 결과.

데이터 추가Map과 UnorderdMap 속도 비교 분홍색Map / 파란색UnorderdMap 

데이터 수 128 개를 넘어가며 map의 검색 속도가 크게 하락된다.

unordered_map 은 800만개 이상 까지 준수하게 좋은 검색 속도를 보여준다.

map은 binary tree 이고, unordered_map 은 hashtable.

unordered_set과 더불어 map 사용할 일이 있으면 unordered_map 사용 하기로..

 

http://supercomputingblog.com/windows/ordered-map-vs-unordered-map-a-performance-study/

 

Ordered map vs. Unordered map – A Performance Study

There comes a time in most complex programs where you want to ask a simple question like, ‘have I already processed a string with this id’? Linear searches through an array are easy to …

supercomputingblog.com

 

https://gracefulprograming.tistory.com/3

 

[C++] map vs hash_map(unordered_map)

개요 hash_map은 비표준 Container인데 반해(stdext namespace에 포함) unordered_map은 C++11에서 STL 표준 Container로 추가되었으며, (사실 TR1부터 추가되었지만 C++11에서 좀 더 최적화가 이루어졌다고 합..

gracefulprograming.tistory.com

 

[C++] map vs hash_map(unordered_map)

https://m.blog.naver.com/PostView.nhn?blogId=rapperkjm&logNo=221038507723&proxyReferer=https:%2F%2Fwww.google.co.kr%2F

 

map과 unordered_map의 속도 비교와 사용의 차이

C++ 11이 적용이 될 즈음부터 Unity를 사용하면서 C# 만 하다가 최근에 다시 C++을 하고 있습니다. 현...

blog.naver.com

 

map과 unordered_map의 속도 비교와 사용의 차이

http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_QnA_etc&no=3392

 

unordered_map과 map과 multimap을 언제 사용하면 좋은가요?

대략 장단점은 생각해 보았는데, 실제 게임을 만들때 어떤 자료구조에 적합한지 예시를 떠오리려니 감이 잘 안오네요.혹시 이 부분에 대해서 아시는 분은 답변 부...

lab.gamecodi.com

 

1.InvalidOperationException: tree modified
-exception
1.Unitwalking die로 Collision list 삭제가 빈번한 상황에서 발생.
2.Error 내용 InvalidOperationException: tree modified.

-exception location
//@ If unit is null, Delete unit from collideList.

List<UnitWalking> listCollideCollect = new List<UnitWalking>();

ICollection<int> collectionID = listCollider.Keys;

 

foreach (int idunit in collectionID) { <-Error

UnitWalking unitWalking = unitpool[idunit] as UnitWalking;

if (null == unitWalking) {

listCollider.Remove(idunit); // <-InvalidOperationException: tree modified

}

else {

if (true == unitWalking.IsUnitDie())

listCollider.Remove(idunit); // <-InvalidOperationException: tree modified

else

listCollideCollect.Add(unitWalking);

}

 

-exception solution
//@ If unit is null, Delete unit from collideList.

List<UnitWalking> listCollideCollect = new List<UnitWalking>();

ICollection<int> collectionID = listCollider.Keys;

List<int> listcollideremove = new List<int>();

 

foreach (int idunit in collectionID)

{

UnitWalking unitWalking = unitpool[idunit] as UnitWalking;

if (null == unitWalking) {

listcollideremove.Add(idunit);

}

else {

if (true == unitWalking.IsUnitDie())

listcollideremove.Add(idunit);

else

listCollideCollect.Add(unitWalking);

}

}

 

//@ for safety elimination

foreach (int idunitremove in listcollideremove)

{

listCollider.Remove(idunitremove);

}

 

2. Shallow copy and destruct original data problem (얕은 복사와 원본 데이터 삭제 오류)

-exception

1.map save 시에 2번 이상 연속 호출 되는 경우 2번째 이후로 저장이 안됨.

2.내부 링크 참조된 list들이 clear()된 이후 접근 된 것.
-exception location

//@ Process : Save

void _SaveAll()

{

// MapSave

    Map.Release();

navigation_toCMapTemplate();

SaveBaseCore();

 

Map.Save();

} // void _SaveAll()

 

public void Release()

{

if (null != CoreList)

{

CoreList.Clear();        <-clear all lists as copy shallow

}

}

 

void _SaveBaseCore()

{

BaseInfo core = null;

foreach (CBASE__ arrBase in m_baseCoreCollector.m_listBase)

{

core = new BaseInfo();

core.Type = arrBase.getIdxType();

core.CellIndex = arrBase._listIdxTris;    <-list copy shallow

core.CoreTriPnt = arrBase._listv3Pnts;    <-list copy shallow

core.CoreTriPntSrc = arrBase._listv3PntsSrc;<-list copy shallow

core.CenterPos = arrBase._v3PositionCenter;

CoreList.Add(core);

}

}

 

-exception solution

1.Deep copy

void _SaveBaseCore()

{

BaseInfo core = null;

foreach (CBASE__ arrBase in m_baseCoreCollector.m_listBase)

{

core = new BaseInfo();

core.Type = arrBase.getIdxType();

core.CellIndex = new List<int>(arrBase._listIdxTris);

core.CoreTriPnt = new List<Vector3>(arrBase._listv3Pnts);

core.CoreTriPntSrc = new List<Vector3>(arrBase._listv3PntsSrc);

core.CenterPos = arrBase._v3PositionCenter;

CoreList. Add(core);

}

}

The Open-Closed Principle

1.OOP // Open-Closed Principle

객체 지향 디자인에 대한 일반적 지식들이 항상 옳을까?
All member variables should be private. 모든 멤버 변수들은 private 되어야만 한다.
Global variables should be avoided. 전역 변수는 피해야만 한다.
Using run time type identification is dangerous. RTTI는 위험하다.

모든 시스템은 그들의 생명 주기 동안 변하며, 오래 지속될 것을 예상하여 시스템 초기 개발에 염두 하여야 한다.

"SOFTWARE ENTITIES(CLASSES, MODULES, FUNCTIONS, ETC.)
SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION."

"소프트웨어 주요구성요소들은 확장에는 개방되어야 하지만, 변형에는 닫혀있어야 한다."

프로그램은 일반적으로 변형되기 쉽고, 외부 영향을 받으며 예측하기 어렵고, 재사용이 어렵다.
Open-Closed Principle 의 2가지 요소
1. Open for Extension 확장을 위한 개방
2. Closed for Modification 변동을 막는 패쇄

일반적으로 모듈의 동작을 확장하려면 모듈의 변화가 야기된다.

어떻게 두 가지 상반되는 요소를 풀수 있을까?
Abstraction is key
Abstraction 추상적 개념을 도입하면 구현이 가능하다.
Abstraction이란 Base 클래스를 추상화 하고 모든 상속 받는 클래스들에게 나타내어지는 경계선 없는 그룹이다.
Abstraction은 변형에 닫혀 있을 수 있고, 새로운 파생을 상속 하게 함으로 확장에는 열릴 수 있다.

OOD solution to Square/Circle problem. // open-closed principle

class Shape
{
public:
virtual void Draw() const = 0;
};

class Square : public Shape
{
public:
virtual void Draw() const;
};

class Circle : public Shape
{
public:
virtual void Draw() const;
};

void DrawAllShapes(Set<Shape*>& list)
{
for (Iterator<Shape*>i(list); i; i++)
(*i)->Draw();
}

2.Advanced Issue DrawAllShapes with Ordering Issue

DrawAllShapes with Ordering

Shape with ordering methods.

class Shape

{

public:

virtual void Draw() const = 0;

virtual bool Precedes(const Shape&) const = 0;

bool operator<(const Shape& s) {return Precedes(s);}

};


void DrawAllShapes(Set<Shape*>& list)

{

// copy elements into OrderedSet and then sort.

OrderedSet<Shape*> orderedList = list;

orderedList.Sort();

for (Iterator<Shape*> i(orderedList); i; i++)

(*i)->Draw();

}

Ordering a Circle

bool Circle::Precedes(const Shape& s) const

{

if (dynamic_cast<Square*>(s))

return true;

else

return false;

}

 

DrawAllShapes with Ordering - ocp

#include <typeinfo.h>

#include <string.h>

enum {false, true};

typedef int bool;

class Shape

{

public:

virtual void Draw() const = 0;

virtual bool Precedes(const Shape&) const;

bool operator<(const Shape& s) const

{

return Precedes(s);

}

private:

static char* typeOrderTable[];

};

 

char* Shape::typeOrderTable[] = { "Circle", "Square", 0 };

// This function searches a table for the class names.

// The table defines the order in which the

// shapes are to be drawn. Shapes that are not

// found always precede shapes that are found.

 

bool Shape::Precedes(const Shape& s) const

{

const char* thisType = typeid(*this).name();

const char* argType = typeid(s).name();

bool done = false;

int thisOrd = -1;

int argOrd = -1;

for (int i=0; !done; i++)

{

const char* tableEntry = typeOrderTable[i];

if (tableEntry != 0)

{

if (strcmp(tableEntry, thisType) == 0)

thisOrd = i;

if (strcmp(tableEntry, argType) == 0)

argOrd = i;

if ((argOrd > 0) && (thisOrd > 0))

done = true;

}

else // table entry == 0

{

done = true;

}

}

return thisOrd < argOrd;

}

 

3.Advanced Issue RTTI is Dangerous.


참고 1.

RTTI violating the open-closed principle.

class Shape {};

class Square : public Shape

{

private:

Point itsTopLeft;

double itsSide;

friend DrawSquare(Square*);

};

class Circle : public Shape

{

private:

Point itsCenter;

double itsRadius;

friend DrawCircle(Circle*);

};

void DrawAllShapes(Set<Shape*>& ss)

{

for (Iterator<Shape*>i(ss); i; i++)

{

Circle* c = dynamic_cast<Circle*>(*i); // violating open-closed principle

Square* s = dynamic_cast<Square*>(*i);

if (c)

DrawCircle(c);

else if (s)

DrawSquare(s);

}

}

 

The difference between these two is that the first, Listing 9, must be changed whenever a new type of Shape is derived.

 

Listing 10

RTTI that does not violate the open-closed Principle.

class Shape

{

public:

virtual void Draw() cont = 0;

};

class Square : public Shape

{

// as expected.

};

void DrawSquaresOnly(Set<Shape*>& ss)

{

for (Iterator<Shape*>i(ss); i; i++)

{

Square* s = dynamic_cast<Square*>(*i);

if (s)

s->Draw(); // not violating open-closed principle

}

}

 

if a use of RTTI does not violate the open-closed principle, it is safe.

참고: http://saraford.net/2010/03/30/speaking-at-devdays-2010-in-the-netherlands-and-techdays-in-belgium-visual-studio-tips-2/

 

Tip #1 How to behold the power of incremental search 

  ctrl+i 로 찾을 문자를 입력하고 ctrl+i로 다음 문자 넘어가기 기능
  

1.Press Ctrl+I

  2.Start typing the text you are searching for.  

    note: 문자를 입력하다 매치되는 문자가 있으면 커서 점핑이 일어나며, 

    찾고자 하는 매치문자는 눈에 띄는 표식.

  3.Press Ctrl+I again to jump to the next occurrence of the search string

  4.(advanced tip) Press Ctrl+Shift+I to search backwards

  5.To stop searching, press ESC 
 

Tip #2 Ctrl+F3 to search for currently-selected word

  Just select some text  (or just have the cursor on the word you wish to search for) 

  and press Ctrl+F3.  

  Ctrl+Shift+F3 will do a reverse search.
 

  단순히 어떤 텍스트를 선택하고 (또는 찾고자 하는 단어 위에 커서를 올려놓고)

  Ctrl+F3을 누르면 알아서 찾는다. 리버스찾기는 Ctrl+Shift+F3

  다음 사항은 주의 할 점 Ctrl+F3:

    -대소문자를 가린다.

    -숨겨진 텍스트를 검색하게 된다.

    -부분적 매치가 되는것을 허락한다.

    -정규화식(regular expressions)를 허용하지 않는다.

 

Tip #4 Customize what files to find in

    ctrl+shift+f 로 전체 찾기 창에서 찾고자 하는 폴더타겟 지정 기능
   
  1.
파일 찾기 윈도우를 보면, "찾는 위치"의 찾고자 하는 단어를 특정한 문서들을 제외하거나 포함 기능으로       

    "이 파일 형식 보기"에서 어떤 파일을 찾을 것인지 확장자를 선택

2.보다 개선된 검색은 "찾는 위치"콤보 박스옆에 "..."버튼
   
3."..."버튼을 누르면 폴더 선택 찾이 뜬다.

 
Tip #5 You can use a reg hack for customizing search results

   찾기 결과 창에 결과 정보의 컬럼을 커스터마이징 하는 기능

  비주얼 스튜디오 찾기 기능에서 찾은 파일결과 값에 각 결과별 경로가 너무 길어서 불편한 점이 있다.

  단지 파일 이름만 결과 값으로 나오기를 원한다면? 

  레지스터 설정에서 몇가지 값을 변경하는 것으로 가능 하며,

  비주얼 스튜디오를 재시작 할 필요 없이 레지스트리만 변경하면 된다.
 

   1.HKCU\Software\Microsoft\VisualStudio\9.0\Find

   2.새로운 string값 "Find result format"을 추가해서 "$f$e($l,$c):$t\r\n" 값을 추가 해본다.

$f is the filename

$e is the extension

$l is the line

$c is the column

$t is the text on the line

 

이후 찾기 창에 결과값을 보면:

 

레지스트리에 등록할 수 있는 각각의 인자값들은 다음과 같다.

Files

     $p path

     $f filename

     $v drive/unc share

     $d dir

     $n name

     $e .ext

 

Location

     $l line

     $c col

     $x end col if on first line, else end of first line

     $L span end line

     $C span end col

 

Text

     $0 matched text

     $t text of first line

     $s summary of hit

     $T text of spanned lines

 

Char

     \n newline

     \s space

     \t tab

     \\ slash

     \$ $

 

Tip #8 How to use box/column selection in the editor

   (Shift+)Alt+→,←,↑,↓ 로 횡 단으로 텍스트 선택 영역을 지정 할 수 있다.
 

   

Tip #20 File tab channel registry hack 

   VS2010은 관련옵션이 이미 있고 2005, 2008에서 가능한 팁으로 약간에 리스크가 있을 수 있다고는 한다.
   HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0

   (DWORD) (UseMRUDocOrdering = 1) 를 추가 해준다.

   편집기 상단 탭들이 MRU (Most Recently Used)로 정렬 된다.

 

   

   

Tip #21 How to show Misc Files Project to keep your files around

   (도구-옵션-환경-문서-솔루션탐색기에 기타파일 표시) 를 체크 하면 (mecellaneous files)기타 파일들을

   솔루션 탐색기 옵션에서 볼 수가 있다.

   이것이 현재 솔루션 밖에 있는 같은 파일들을 지속적으로 살펴보고자 할 때 매우 유용하다.

   예를들어, 테스트 라이브러리를 경유하여 이 테스트를 하려는 경우, 

   테스트 케이스를 솔루션 자체에 보유해야만 하고 테스트 라이브러리 DLL들을

   연결 해야만 하는데, 이러한 파일들을 (miscellaneous files) 기타파일들 아래 모아두면 유용하다. 

   

Tip #23 You can use tracepoints to log stuff in your code

   값들에 대한 로그값을 보고 싶을 때 일반적으로 Console.Writeline() 이나 PrintF(), OutputDebugString(str)

   등을 쓰게 되는데 2008이후로 추적점(tracepoints) 이라는 기능이 생겨서 흐름상 추적을 할 수가 있다.

   예를들어 Debug컴파일 이후 특정 변수의 Output 창에서 값을 확인 하고 싶으면

   Value of *vertexData is {*VertexData} 런식으로 {} 내의 값이 실제 값으로 출력이 된다.

 1.새로운 트레이스 포인트(추적점) 추가

2.



3.에디터에서 다이아몬드 점을 확인


4.결과

SRP:

The Single Responsibility Principle / 단일 책임 원칙

None but Buddha himself must take the responsibility of giving out occult secrets...

— E. Cobham Brewer 1810–1897.

Dictionary of Phrase and Fable. 1898.
이 원칙은 1.Tom DeMarco와 2.Meilir Page-Jones에 작업에 의해 기술 되었고,
그들은 이것을 응집력이라고 불렀으며, 21챕터에서 볼 것으로써, 패키지 레벨에 응집력의 보다 명확한 정의를 
다룰 것이지만 클래스 레벨상에 정의는 거의 비슷하다.

SRP: The Single Responsibility Principl

클래스를 변경하기 위한 하나 이상의 이유가 있어선 안된다.챕터 6에서 다룬 볼링 게임을 예를 들면 게임 클래스의 개발에 대부분을 위하여 2가지 책임을 분리해
다뤘는데, 현재 프레임에 트랙을 유지하는 것과 스코어를 계산하는 것이었다. 마지막으로는 RCM과
RSK라는 두개의 책임들을 두개의 클래스로 분리 해냈다.
Game은 프레임의 트렉 유지 책임을, Scorer는 스코어를 계산하는 책임을 유지했다. (85페이지)

1. [DeMarco79], p310
2. [PageJones88], Chapter 6, p82. 
중요한 이러한 두 개의 책임들을 각각 분리된 클래스로 다루는 것이 왜 중요할까?
왜냐하면 각각의 책임들은 변동의 축이 되기 때문이다. 어떤 변동이 요구가 될 때, 그 변화는 클래스들 사이에 
변동의 책임이라는것을 통해 명백하게 될 것이다. 만약 한 클래스가 한 개의 책임 이상을 가정한다면, 변동를 위해서는 한 개
이상의 이유가 있어야 할 것이다.

만약 한 클래스가 한 개 이상의 책임을 가진다면, 책임들은 상호간 결속되어 지는데,
한 개의 책임이 변하게 되면 다른 클래스들을 만나는 클래스적 기능이 감소되거나 방해가 될수 있으며,
이러한 종류의 상호간 결속력은 변동이 생길 때에 기대하지 않은 방향으로 쉽게 깨져버리게 된다.

예를들면, 9-1에서 사각형클래스에 두개의 메쏘드들을 보유하고 있고, 한개는 화면상에 사각형을 그리고, 다른 하나는 사각형 
영역을 계산한다.

두개의 다른 응용프로그램이 사각형 클래스에서 사용된다.

우선 하나는 기하학적 계산을 하는데, 기하학 모형에 수학적 연산을 돕기위해 사각형클래스를 사용하여 사각형을 화면상에
그리지는 않는다.
다른 응용프로그램은 그래픽적으로 작용하며 또한 기하학적인 연산처리를 하지만 명확한것은 화면상에 사각형을 그리는
역활을 한다.
이 클래스 디자인은 SRP(Single Responsibility Principle)을 어기고 있다.
사각형 클래스는 2개의 책임을 지고 있는데, 첫번째 책임은 사각형의 기하학적 모델의 수학적 부분을 제공하고,
두번째 책임은 그래픽적인 사용자 인터페이스 로써 사각형을 그리는 것이다.
SRP를 어기는 것은 몇몇 귀찮은 문제들을 야기한다.
우선적으로, 기하학적 연산처리 응용 프로그램내에서 GUI를 포함해야만 하며, 
만약 C++응용 프로그램이라면, GUI는 내부적으로, 메모리 추적, 컴파일 시간, 링크소비 시간을 링크를 해야 할 것이다.
자바 응용 프로그램이라면, .class파일들을 위한 GUI는 목표 플랫폼에 맞게 전개 되어야 한다.
두번째로, 만약 몇가지 이유로 GraphiclaApplication의 변동이 사각형클래스의 변동을 야기 한다면, 그 변동은 강제적인 리빌드,
재검사, 
  ComputationalGeometryApplication 이동을 요구 할 수도 있다.
만약 이것을 잊어버린다면, 그 응용 프로그램은 예측 불가능한 방향으로  돌변 할 수도 있다.
더 나은 디자인은 참조 9-2에서 보여주는것처럼 완벽하게 다른 클래스들로 두개의 책임을 각각 분리 하는것이다.
이 디자인으로 사각형의 연산처리부분은 GeometricRectangle 클래스로 이동 되었다.
이제 변동으로 렌더링되는 사각형은 ComputationalGeometryApplication에 영향을 줄 수 없는 방법이 적용되었다.
 

여기서 이제 책임이 무엇인가?

구문상에 있어 단일 책임 원칙(SRP-Singlt Responsibility Principle)을 "변동을 위한 하나의 동기"를 책임으로 정의하였다.

 

만약 독자가 한클래스에 변동을 위한 한개의 동기 이상을 생각 한다면, 그 클래스는 한개 책임 이상을 가지게 된다.

 

이것은 때때로 어렵다. 여기 그룹내 책임을 생각하기 위해 익혀보도록 하자. 예로써 모뎀 인터페이스를 간주하였다.

 

Listing 9-1

Modem.java -- SRP Violation

interface Modem

{

public void dial(String pno);

public void hangup();

public void send(char c);

public char recv();

}

2개의 책임들이 여기서 보여진다. 첫째는 연결 관리이고, 두번째는 데이터 상호간 통신이다. dial과 hangup 함수는 모뎀의
연결을 관리하고 send, recv 함수는 통신을 관리한다. 
이 두개의 책임들은 분리 되어야만 할까? 명확하게 그렇다.  
두개의 셋 함수들은 거의 상호간 공통분모가 없다.

그것들은 각각 명확히 다른 이유의 변동이며, 거기다가 각각의 함수들을 사용하는 응용프로그램 부분까지 명확히 구획이 

 

나누어져 호출된다. 이 두개의 서로다른 단위는 서로 다른 이유에 잘 변동이 될 것이다.

그러함으로 참조 9-3은 더 나은 클래스디자인을 보여준다. 그것은 두개의 분리된 인터페이스로 들어가는 책임들로 구분되어졌다.
이것은 적어도, 두개의 책임들의 연관성으로부터 클라이언트 프로그램을 유지시켜준다. 

그러나, 주목할 것은 단일 ModemImplementation 클래스 내에 두개의 책임들이 재연관을 맺었다는 것 이다.

 

이것은 바람직하지 않지만 필요가 있다.

 

종종 어떤 하드웨어나 운영체제의 세부적인 사항들을 처리를 하기 위한 이유 등으로 인해 어쩔 수 없이 상호 연관을 가지게 되는

 

경우가 생긴다.

 

그러나, 그들의 인터페이스를 나눔으로 응용프로그램이 관련된 나머지에 관하여 개념적인 분리를 할 수가 있다.
ModemImplamentation 클래스는 적합하지 않을지도 모른다. 그러나 주목할 것은 모든 비독립적인 것들로 부터 멀리하라는 

 

 것이다. 

 

 

 

Conclusion / 결론

단일 책임 원칙(Single Responsibility Principle) 은 하나의 단순한 원칙이고 올바르게 구현하기가 가장 어려운 디자인들 중
하나이다.

 

책임들을 결합 하는 것은 자연스러운 결과이며, 다른 하나로부터 여러 책임들을 찾아내고 분리해내는 것이 실제적인

 

소프트웨어 디자인의 상당 부분을 차지한다. 나머지 원칙들에 대해서 다루다 보면 한가지 또는 다른 방식으로 이 이슈가

 

다시 논의 될 것이다.

Bibliography

[DeMarco79]: Structured Analysis and System Specification, Tom DeMarco, Yourdon

Press Computing Series, 1979

[PageJones88]: The Practical Guide to Structured Systems Design, 2d. ed., Meilir PageJones, Yourdon Press Computing Series, 1988

OVERRIDING INTERFACE METHODS IN SUBCLASSES
// 상속클래스에서 재정의 되는 인터페이스 메서드

내용에 앞서:

언급된 관련 서적 :

1. Don Box's Essential .NET Volume 1

번역 :
1.Polymorphism : 다형성, 다형적

2.Mathod signature : 메서드 서명, 메서드 식별자
(이를테며 void a(int i), void a(int i, float f) 오버로딩 함수라면 반환타입, 인자갯수, 인자 타입등..)

3.SubClass : 상속된 클래스

4.Override : 재정의

5.Implementation : 인터페이스의 최종 구현부 //(Java의 final)

내용 :

C#(일반적으로 닷넷)은 상속된 클래스 내부의 메소드들의 재정의을 위한 virtual/abstract와 계층적 구조를

 이용한 다형성을 제공합니다.

얼핏 보기에, C#은 그 개념에 있어서 C++과 Java 둘다의 특징을 보이지만, 그것은 피상에 불과합니다. 

C#에서 인터페이스를 정의는 다음과 같습니다.

public interface IFoo {

void doSomething();

}
코드참고1.

 


클래스A를 정의하여 인터페이스로 구현을 하게 됩니다.

public class A : IFoo {

public void doSomething() {

Console.WriteLine("In A.doSomething()");

}

}
코드참고2.

 

A를 IFoo 인터페이스로써 사용할 수 있습니다.

 

IFoo foo = new A();

foo.doSomething(); //outputs: In A.doSomething()
코드참고3.


기본적인 예로써, 이것이 가능한 것은 닷넷 런타임이 IFoo.doSomething()을 참조하는 곳에 A.doSomething()
을 찾아내며 오브젝트 참조의 메모리 출력되는 주소 공간을 조작하여 이루어 집니다.

이것은 언어에 따라 다르지만, 일반적으로 (간단하게) 개체에서 지원하는 각 유형의 구현에 매핑 개체에서 사용할 각 방법에 대한 주소 위치의 목록을 하나 이상 vtables를 사용하는것을 포함합니다.

가상 메서드들이 vtable로 컴파일 되는 시점에, 일반적인 메서드들은 자신들의 주소들을 가지는 코드안으로 컴파일이 되며,
이 포인터는 런타임 시점에서 언어가 가지는 다형성 규칙과 특정 참조에 따라 실제 메서드의 위치로 변환됩니다.
 일단
virtual 표기 되면, 함수의 메서드 서명은 타입 계층을 통한 virtual 유지됩니다

 virtual 표기 되면 메소드 서명에 대한 호출은 항상 어디 유형 계층 구조에 있는 참조 점에 관계없이 조회 vtable list 통해 이동 합니다.

 

인터페이스도 타입이므로, 정의된 인터페이스 메서드는 가상이기 때문에 이로써, 정의된 인터페이스 메서드는

재 정의가 될 수가 있습니다.

 C#에서(C++동일, Java제외) 정의된 가상 메서드들은 일반적으로 그들의 서명으로 표기되는 'virtual'키워드가 요구 됩니다.
 (그래서 컴파일러는 메서드의 실제 주소값 대신 추가된 vtable 진입점을 알고 있게 됩니다.)

 구현을 위해 인터페이스 메서드 서명을 상속하는 클래스들이 확실하게 요구하는 동안 인터페이스들의 요청은 잠시

보류가 됩니다.

(엄밀히 말해서 인터페이스들은 구현되는 클래스들의 기본 타입은 아니며, 이에 대한 자세한 정보는 
 Don Box's Essential .NET Volume 1 책의 70페이지를 활용바랍니다.)

   

또한 C#(C++동일,Java제외)에서 또다른 키워드 'override'는 메서드 서명의 vtable진입점으로 변환되기 위해 하위 클래스에서 요청을 하게 됩니다.

결과적으로, C#의 'sealed' 키워드(Java의 'final'과 동일)는 비-가상 메서드를 만들수 없게 만들지는 못해도,
하위 클래스에서 'sealed' 키워드가 선언된 인터페이스를 재 정의를 못하게 할 수는 있습니다.

 virtual 메서드 서명들은 상속 클래스에 vitual로 남게 되고, 인터페이스 메서드들이 virtual가 되면 인터페이스 메서드로써

상속 클래스들의 클래스들에서 구현 부 인터페이스들로써의 재정의가 가능하게 됩니다.
 이하 코드는 이상 내용의 참고:

public class A : IFoo {

public void doSomething() {

Console.WriteLine("In A.doSomething()");

}

}
코드참고4.

public class B : A {

public override void doSomething() {

Console.WriteLine("In B.doSomething()");

}

}
코드참고5.

C#에서 동작하지 않고 다음 에러문구를 출력합니다:

B.doSomething()' : cannot override inherited member 'A.doSomething()'

because it is not marked virtual, abstract, or override

//B.doSomething() : A.doSomething()를 구성요소로써 재정의 할 수 없습니다.
A.doSomething()에 virtual, abstract 또는 override 표시가 없기 때문입니다.//

A를 간단히 해서 'override' 를 메서드 정의에서 제외 시키면 다음과 같이 출력됩니다.

public class B : A {

public void doSomething() {

Console.WriteLine("In B.doSomething()");

}

}
코드참고6.


컴파일 되지만 원하는 결과가 또한 아니며 다음의 경고 메세지를 알려주게 됩니다.:

The keyword new is required on 'B.doSomething()' because it hides inherited member 'A.doSomething()'
new 키워드가 'B.doSomething()'에 필요합니다. 상속 상위 개체 함수'A.doSomething()'에 의해 숨겨졌습니다.

"상속 상위 개체 맴버에의해 숨겨지다" 라는 의미를 해석해 보자면
 C#(C++동일,Java제외)은 저러한 기반 클래스들의 동일한 서명을 가진 상속클래스들의 메소드들을 허용합니다.
 여기서 다시 상기 해보자면 virtual 키워드로 구현된 것이 아니라면 'vtable'목록에 포함되지 않습니다. 
 쉽게 말하자면 B는 두 개의 doSomething()메서드를 가지게 됩니다.
 결과 인식 메서드는A로부터 상속 받은 것, 그리고 B에서 새로 정의한 것 2개가 되며, 그런 이유로 new 키워드가
새로 필요하다는 경고 메세지를 출력하게 됩니다.
 또한 다음에서 보듯, IFoo로써 B를 사용하는 것은 의도하는 바가 아닙니다.

IFoo foo = new B();

foo.doSomething(); //outputs: In A.doSomething() // 원하는 결과가 아님.

한가지 해결점은 'virtual' 메서드를 A.doSomething()앞에 표시하는 것이지만 만약 A 코드에 접근할 수 없는 상황이라면
어떻게 해야할까요?





C#상에서 모든 것을 충족시키는 IFoo의 구현부인 B로써는 다음과 같습니다:

public class B : A, IFoo {

void IFoo.doSomething() {

Console.WriteLine("In B.doSomething()");

}

}

IFoo foo = new B();

foo.doSomething(); //outputs: In B.doSomething()

코드참고7.

그러나 위 사항은 저장 영역으로 B는 다른 syntax임을 주목 해야 합니다.
'public' 키워드를 제외시킴으로써 IFoo.doSomething의 구현을 명확하게 할 수가 있습니다. 
 이전과 같은 경고와 에러가 뜨지 않게 하려면, A에서 했던 것과 같은 단순화된 메소드를 구현할 수는 없습니다. 
이것은 외부 구현부에서 변경하여, 이 클래스 선언을 통해 B를 private 하게 하고 public 키워드를 삭제할 필요가 있습니다.
B에서 구현된 doSomething()은 인스턴스화 된 B에서는 접근 안되며, IFoo에서만 가능합니다.

   

B b=newB();
A a =b;

b.doSomething(); //outputs: In A.doSomething() !!
a.doSomething(); // 역시나 위와 동일한 결과


Essential .NET Volume 1 page 169:

...the implementation of an interface method is implicitly 'final', just as if
the 'sealed' and 'override' modifiers were present.

...인터페이스 메서드의 구현부 에서 선언은 'final'이며, 'sealed'나 'override' 또한 제공됩니다.

인터페이스 메서드를 구현하기 위해서는 sealed 키워드를 사용 해야 하며,
 다르게 보자면 C#에서는 첫 번째 인터페이스 마지막 구현부 에서는 override 로 연결되는 것입니다.

 
C#(.NET)은 뚜렷한 base class designer(기반 클래스 디자이너)의 디자인 결정을 해야 하는 일종에 디자인 철학을

준수합니다.

 어떤 클래스들이 확장 되고자 한다면 명백하게 표기가 되어야 합니다.
반대로 말하면, C++은 무엇인가가 명백화 해줄 필요가 있는, 또한 자바가 그러한, 최종 결과를 지어줄 수 있는 그러한

클래스 디자이너가 제공되지 않고 기본적으로 모든 메서드 들은 가상화 됩니다.
 이것은 보다 많은 토론의 여지가 있는 주제 이지만 필자의 생각으로는 이것은 가능한 것과 직관적인 것 사이에 있어 디자인적인 선호도로 부터 파생된 결과라고 생각합니다.
 필자는 기술적으로 가능한 디자인의 사용을 더욱 선호 합니다.

그러나, 언어 디자인 선택에 관해 논쟁을 펼치는 것은 "돈키호테"와 같다고 믿기 때문에, 근래 들어 개인적으로 선호 하는 것 은 진행해 보고, 함정들을 표시하고, 왜 그것들이 거기 있는지 이해하고, 그것들을 옮기는 방식입니다.

'Programming > Design' 카테고리의 다른 글

OCP : The Open-Closed Principle  (0) 2011.08.05
SRP : The Single Responsibility Principle  (0) 2011.07.18

Intersect ray Math Function

 

1. 함수 소개 : Projection Vector

: Vector3 CMath.ProjectionVector(Vector3 v3DirVelocity, Vector3 v3DirNormal)

.개요: 일반적으로 다 알고 있는 투영벡터이지만 어떻게 활용하는지에 따라 그 유용성을 재 확인
.어떻게 활용 : Gizmo, UnitWalking
.함수 위치 : MATH.ProjectionVector
.수식 : Position Projection = PosObj + (DirN(Normalized) * Dot(DirN, DirDistanceA))

.유의점 : Normalize연산


참고1.


 

//@ Projection vector Src to Dst, return Vector has Dir & Distance.

public static void ProjectionVector(

Vector3 v3DirDistance,

Vector3 v3DirProjectionBase,

out Vector3 v3DirDistancePrj)

{

v3DirDistancePrj = v3DirProjectionBase * Vector3.Dot(v3DirDistance, v3DirProjectionBase);

}

 

참고2. 일반적으로 Sliding vector로 불리우는 공식 또한 Projection Vector와 동일

 

2. 함수 소개 : Ray-Plane Intersect

: public static bool IntersectRayPlane( Vector3 v3PosRay,

Vector3 v3DirRay,

float fDistanceRay,

Vector3 v3PosPlane,

Vector3 v3DirNormalPlane,

ref Vector3 v3PosIntersected)

.개요: Ray-Plane 충돌점은 비슷한 함수가 Engine내 제공되나 공간자료구조검색 + 면충돌 여부판별+충돌점계산 연산으로
면충돌 여부판별과 충돌점 계산을 완료.

.어떻게 활용 : 추후 UnitWalking에 활용 예정
.함수 위치 : MATH. IntersectRayPlane
.수식 :
Ray => PosRay + (distance)DirRay;
Plane => -Dot(PosPlane,DirPlane) = d
PosPlane에 PositionRay 대입 => Dot((PosRay+( distance)DirDistanceRay), DirPlane) + d = 0

.유의점 : 함수는 꼭지점을 가진 면 내부 충돌 여부 판정이 아님.

 

참고3.


참고4.

//@ Ray-Plane Intersect

public static bool IntersectRayPlane( Vector3 v3PosRay,

Vector3 v3DirRay,

Vector3 v3PosPlane,

Vector3 v3DirNormalPlane,

ref Vector3 v3PosIntersected)

{

float fD = -Vector3.Dot(v3PosPlane, v3DirNormalPlane);

 

float fVdotN = Vector3.Dot(v3DirRay,v3DirNormalPlane);

if(0==fVdotN)

{

return false;

}

 

float fSDotN = Vector3.Dot(v3PosRay, v3DirNormalPlane);

 

float fT = -(fSDotN + fD) / fVdotN;

 

if (0 == fT)

{

return false;

}

 

v3PosIntersected = v3PosRay + (v3DirRay * fT);

 

return true;

} // public static bool IntersectRayPlane

3. 함수 소개 : 2D Line cross
:
bool doesLineCross2D_est_test( Vector3 v3Pos01_start,

Vector3 v3Pos01_end,

Vector3 v3Pos02_start,

Vector3 v3Pos02_end )
.개요 : Navigation mesh3D상에 가시성 검사 같은 무수히 많은 Intersect ray검사는 과연산량으로 이에 대한 방안으로
2D Line cross를 이용한 유닛이 특정 위치점에 갈 수 있는지 여부 판단.

.어떻게 활용 : 가시성을 고려한 최단거리 유닛 이동처리.
.함수 위치 : CMath.doesLineCross2D_est_test

.유의점 : Navigation mesh가 복층 같이 겹친곳에서 연산 중복


참고5.
public bool DoesCrossEdge2D(Vector3 v3Pnt0_, Vector3 v3Pnt1_)

{

Vector2 v2Pnt0_ = new Vector2(v3Pnt0_.x, v3Pnt0_.z);

Vector2 v2Pnt1_ = new Vector2(v3Pnt1_.x, v3Pnt1_.z);

 

return CMATH.doesLineCross2D_est_test(_v2Pnt0, _v2Pnt1, v2Pnt0_, v2Pnt1_);

}

public static bool doesLineCross2D_est_test(Vector2 v2Pos0_start,

Vector2 v2Pos0_end,

Vector2 v2Pos1_start,

Vector2 v2Pos1_end)

{

// Denominator for ua and ub are the same, so store this calculation

float d =

(v2Pos1_end.y - v2Pos1_start.y) * (v2Pos0_end.x - v2Pos0_start.x)

-

(v2Pos1_end.x - v2Pos1_start.x) * (v2Pos0_end.y - v2Pos0_start.y);

 

//n_a and n_b are calculated as seperate values for readability

float n_a =

(v2Pos1_end.x - v2Pos1_start.x) * (v2Pos0_start.y - v2Pos1_start.y)

-

(v2Pos1_end.y - v2Pos1_start.y) * (v2Pos0_start.x - v2Pos1_start.x);

 

float n_b =

(v2Pos0_end.x - v2Pos0_start.x) * (v2Pos0_start.y - v2Pos1_start.y)

-

(v2Pos0_end.y - v2Pos0_start.y) * (v2Pos0_start.x - v2Pos1_start.x);

 

// Make sure there is not a division by zero - this also indicates that

// the lines are parallel.

// If n_a and n_b were both equal to zero the lines would be on top of each

// other (coincidental). This check is not done because it is not

// necessary for this implementation (the parallel check accounts for this).

if (d == 0)

return false;

 

// Calculate the intermediate fractional point that the lines potentially intersect.

float ua = n_a / d;

float ub = n_b / d;

 

// The fractional point will be between 0 and 1 inclusive if the lines

// intersect. If the fractional calculation is larger than 1 or smaller

// than 0 the lines would need to be longer to intersect.

if (ua >= 0d && ua <= 1d && ub >= 0d && ub <= 1d)

{

return true;

}

 

return false;

} // public static bool doesCrossLineEst_test

 

stl containers : http://www.cplusplus.com/reference/stl/
stl algorithms : http://www.cplusplus.com/reference/algorithm/

 

STL Containers: 

bitset 

deque

list

map

unordered_map

multimap

multiset

priority_queue

set

unordered_set

statck

vector

+ Recent posts