C로 클래스 흉내낼 수 있나여?

moonzoo의 이미지

C에서 구조체를 이용해서 클래스 흉내를 낼 수 있는지 궁금합니다.

멤버 변수와 멤버 함수가 있다고 할 경우에..

멤버 함수는 함수 포인터를 이용하면 가능하겠는데.

문제는. 멤버 함수에서 자신을 콜한 인스턴스의 멤버 변수에

어떻게 접근할 수 있을까? 입니다.

C++에서는 this 를 이용하지만 C에서는 어떤 테크닉이 있나여?

댓글

김경태의 이미지

상속 -> 됩니다. pointer to structure 입니다.
method -> 됩니다. pointer to funtion 입니다.
encaptualation(맞나?) -> protect, private 등은 compiler 차원에서 지원되는 것 같습니다.
aggregation -> nested structure 입니다.

pure virtual function-> 됩니다. a->b->c(); 로 합니다.
over loading -> 이건 compiler에서 지원하는 듯 합니다.
name mangling 맞나? 암튼 a() -> a123()
과 같이 실제 컴파일러에서는 다른 이름을 사용
함으로서 같은 이름의 다른 펑션을 구분합니다.
over riding -> pure virtual function과 마찬가지 원리입니다.
소멸자, 생성자-> 당연됩니다. pointer to function입니다.
this pointer -> pointer to function에다 self structure의 pointer를 넘겨줍니다. ^^;

이거 말고 뭘 또 원하시는지?
대표적인 예는 tcp/ip stack이나 VFS source를 보세요.

OO의 개념은 시스템적으로 보면 code segment와 data segment의 <결합>입니다.

그러나 이 <결합>을 이루기 위해 기계적인 실행 파일에서 물리적으로 두 영역을 붙여놓는 것은 불가능합니다.

따라서 이러한 <결합>을 하나의 메모리 영역을 만듦으로서 구현하기 보다 pointer to function이라는 매개체를 통하여 구현함으로서 일반 구현자는 마치 code segment와 data segment가 물리적으로 완벽하게 <결합>되어 있는 것처럼 느끼고 이것을 객체라 부르며 이를 사용하고 있습니다.

하지만 역시 원천을 따지고 보면 이런 구현을 가능하게 한 것은 바로 C에서 제공하는 유연한 pointer to function을 이용하지 않고는 불가능한 스토리입니다.

아니 뭔의 이미지

"이거 말고 뭘 또 원하시는지?" 라니요.

대답 해줄거면 좀 친절하게좀 해주세요 이러니 KLDP 말싸가지 밥말아 처먹었다는 소릴 듣지

세벌의 이미지

kldp는 여러 사람이 옵니다.
불친절한 사람도 오고, 친절한 사람도 오지요.

님께서는 2005년 글에 2018년에 쓰레드 주제와 관계없는 댓글로 kldp 트집 잡으러 오신 건가요?
KLDP 말싸가지 밥말아 처먹었다는 소릴 듣지
라는 글을 쓰신 아니 뭔 님은 누구신가요?
무슨 의도로 이런 글을 쓴 건가요?

익명 사용자의 이미지

김경태 wrote:

OO의 개념은 시스템적으로 보면 code segment와 data segment의 <결합>입니다.

그러나 이 <결합>을 이루기 위해 기계적인 실행 파일에서 물리적으로 두 영역을 붙여놓는 것은 불가능합니다.

따라서 이러한 <결합>을 하나의 메모리 영역을 만듦으로서 구현하기 보다 pointer to function이라는 매개체를 통하여 구현함으로서 일반 구현자는 마치 code segment와 data segment가 물리적으로 완벽하게 <결합>되어 있는 것처럼 느끼고 이것을 객체라 부르며 이를 사용하고 있습니다.

하지만 역시 원천을 따지고 보면 이런 구현을 가능하게 한 것은 바로 C에서 제공하는 유연한 pointer to function을 이용하지 않고는 불가능한 스토리입니다.

아는 대로 이야기 해서
OO 의 개념은 code segment와 data segment의 <결합>이 아니라.
구성요소가 코드와 데이타일 뿐입니다.

코드와 데이타가 합쳐졌다고 객체가 되는것이 아니라
객체의 구성요소에 코드와 데이타가 있는것입니다.

말로 이야기 할려니까 잘 말이 안나오는군요~
암튼 두개는 약간 다른 이야기 입니다.

객체지향을 구현할려면 C++ 로 하는게 좋지 C 로 하면 안하니만 못한 결과가 있을수 있습니다.

마지막으로 데이타와 코드 모두 동일한 메모리 공간에 저장되어 있는걸로 알고 있습니다. 때문에 pointer to function 이 가능한것이죠.

익명 사용자의 이미지

무슨 말씀을 하시는지 잘 모르겠습니다.

happyjun의 이미지

class TestClass
{
 public:
    int badMember;
    void test(int x) {...}
};
int main()
{
    TestClass testClass;
    testClass.test(3);
}

...
struct TestStruct
{
    int badMember;
    void (*test)(TestStruct*, int);  
};
void TestStruct_test(TestStruct*, int x) {}...

int main()
{
    TestStruct testStruct;
    testStruct.test = &TestStruct_test;
    testStruct.test(&testStruct, 3);  // or TestStruct_test(&testStruct, 3);
}

encapsulation은 대강 다음과 같이 할 수 있습니다.

/* in header */
struct PrivateInterface;

struct PublicInterface
{
    PrivateInterface* privateDataOrFunction;
    int publicData;
}

/* in code */
struct PrivateInteface
{
    ....
}

----------------------------------------
http://moim.at
http://mkhq.co.kr

doseon의 이미지

예~~전에 찾아 놓은 문서가 있길래
혹시 도움이 될까해서..

http://ldeniau.home.cern.ch/ldeniau/html/oopc/oopc.html
http://www.planetpdf.com/codecuts/pdfs/ooc.pdf

내용은 잘 기억이 안나지면,
꽤 흥미있게 읽었었습니다.

Fe.head의 이미지

C++ 소스

class Person {
 int age;
public:
 void setAge(const int age);
 int getAGe() const;
};

이걸 C로 구현하면 아래와 같습니다.

#include <stdio.h>

struct Person {
 int age;
 void (*setAge)(struct Person * this, const int age);
 int (*getAge)(const struct Person * this);
};

void Person_setAge(struct Person * this, const int age)
{
  this->age = age;
}

int Person_getAge(const struct Person * this)
{
 return this->age;
}

void Person_init(struct Person * this)
{
 this->setAge = Person_setAge;
 this->getAge = Person_getAge;
}

void Person_destroy(struct Person * this)
{
}

int main()
{
 struct Person minsu;

 /* 생성자 호출 */
 Person_init(&minsu);

 minsu.setAge(&minsu, 10);
 printf("%d\n", minsu.getAge(&minsu));

 /* 소멸자 호출 */
 Person_destroy(&minsu);
 return 0;
}

this는 인자로 들어가죠.

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

코퍼스의 이미지

일단 관련자료도 영문으로 된 것을 인터넷으로 찾으실 수 있을겁니다.

그리고 님이 원하시는 성격의 작업이라면 커널 쪽 핸들러를 사용한 구현 부분을 찾아보시면 공부에 도움이 되실 겁니다.
(예를 들어, 네트워킹 쪽 루틴이나... 디바이스 드라이버쪽 작업 부분 등)

fehead 님의 C 예제는 엄밀히는 C가 아니라 C++ 컴파일러의 도움을 받아야 가능한 구문으로 알고 있습니다.

A few Good Man

Fe.head의 이미지

코퍼스 wrote:

fehead 님의 C 예제는 엄밀히는 C가 아니라 C++ 컴파일러의 도움을 받아야 가능한 구문으로 알고 있습니다.

Person * this 말씀이신가요?
struct Person * this 로 바꿨습니다.^^

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

moonzoo의 이미지

답변 주신분들 매우 감사합니다.

막연하게 머리속에 맴돌던게..예제까지 들어주시니까.

바로바로 정리가 됩니다.

질문 올리고 점심 먹고 왔는데

답변이 일케 팍팍~ 올라올 줄이야..

다들 식사 안하시나여 --a

김경태의 이미지

Anonymous wrote:
김경태 wrote:

OO의 개념은 시스템적으로 보면 code segment와 data segment의 <결합>입니다.

그러나 이 <결합>을 이루기 위해 기계적인 실행 파일에서 물리적으로 두 영역을 붙여놓는 것은 불가능합니다.

따라서 이러한 <결합>을 하나의 메모리 영역을 만듦으로서 구현하기 보다 pointer to function이라는 매개체를 통하여 구현함으로서 일반 구현자는 마치 code segment와 data segment가 물리적으로 완벽하게 <결합>되어 있는 것처럼 느끼고 이것을 객체라 부르며 이를 사용하고 있습니다.

하지만 역시 원천을 따지고 보면 이런 구현을 가능하게 한 것은 바로 C에서 제공하는 유연한 pointer to function을 이용하지 않고는 불가능한 스토리입니다.

아는 대로 이야기 해서
OO 의 개념은 code segment와 data segment의 <결합>이 아니라.
구성요소가 코드와 데이타일 뿐입니다.

코드와 데이타가 합쳐졌다고 객체가 되는것이 아니라
객체의 구성요소에 코드와 데이타가 있는것입니다.

말로 이야기 할려니까 잘 말이 안나오는군요~
암튼 두개는 약간 다른 이야기 입니다.

객체지향을 구현할려면 C++ 로 하는게 좋지 C 로 하면 안하니만 못한 결과가 있을수 있습니다.

마지막으로 데이타와 코드 모두 동일한 메모리 공간에 저장되어 있는걸로 알고 있습니다. 때문에 pointer to function 이 가능한것이죠.

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

정확하게 <결합>이란 의미를 설명하자면 프로그래머가 function과 그 대상인 데이타를 하나의 자료구조(그것이 structure든 class든 간에)로 인식될 수 있어야 한다는 말입니다.

실제로 class든 structure든 data와 method는 process 내부 공간안에 존재하기 때문에 process 내부 메모리에 같이 존재한다는 의미에서는 동일한 메모리에 위치한다고도 할 수 있습니다.

하나 그 동일한 메모리 공간에 위치한다는 말씀이 class에서 보여지는 것처럼 바로 인접한 메모리에 method와 data가 존재한다는 의미로 오해할 수 있는 소지가 충분히 있습니다.

데이타와 코드 모두 동일한 메모리 공간에 저장되어 있다고 하셨지만 제가 말하고자 했던 것은 실제 메모리상에서 활성화된 process 단위에서 데이타와 코드가 class에서 보여지는 것처럼 실제로 인접하고 있느냐 하는 점을 말씀드린 것입니다.

가령 structure 안의 pointer to function과 data들이 인접주소에 있을 수 있겠지만 pointer to function이 가리키고 있는 function과 data가 인접공간에 즉, 0001 0002 0003 0004 이런식으로 저장되어 있다면 그것은 사실이 아닙니다.

또한 일반적으로는 객체지향을 C++로 구현하는 것이 C로 구현하는 것보다 OO를 <더 쉽게!> code상에 구현하는 것은 맞지만 그렇다고 C로 구현한 OO가 모두 불완전하다고 단정하는 것도 또한 무리입니다.

그렇게 말씀하신다면 C로 매우 우아하게 객체지향을 구사해놓은 linux kernel의 설계자들은 안하니만 못한 코딩을 하는 저급 코더로 전락할 수 밖에 없겠지요.

익명 사용자의 이미지

김경태 wrote:

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

정확하게 <결합>이란 의미를 설명하자면 프로그래머가 function과 그 대상인 데이타를 하나의 자료구조(그것이 structure든 class든 간에)로 인식될 수 있어야 한다는 말입니다.

실제로 class든 structure든 data와 method는 process 내부 공간안에 존재하기 때문에 process 내부 메모리에 같이 존재한다는 의미에서는 동일한 메모리에 위치한다고도 할 수 있습니다.

하나 그 동일한 메모리 공간에 위치한다는 말씀이 class에서 보여지는 것처럼 바로 인접한 메모리에 method와 data가 존재한다는 의미로 오해할 수 있는 소지가 충분히 있습니다.

데이타와 코드 모두 동일한 메모리 공간에 저장되어 있다고 하셨지만 제가 말하고자 했던 것은 실제 메모리상에서 활성화된 process 단위에서 데이타와 코드가 class에서 보여지는 것처럼 실제로 인접하고 있느냐 하는 점을 말씀드린 것입니다.

가령 structure 안의 pointer to function과 data들이 인접주소에 있을 수 있겠지만 pointer to function이 가리키고 있는 function과 data가 인접공간에 즉, 0001 0002 0003 0004 이런식으로 저장되어 있다면 그것은 사실이 아닙니다.

또한 일반적으로는 객체지향을 C++로 구현하는 것이 C로 구현하는 것보다 OO를 <더 쉽게!> code상에 구현하는 것은 맞지만 그렇다고 C로 구현한 OO가 모두 불완전하다고 단정하는 것도 또한 무리입니다.

그렇게 말씀하신다면 C로 매우 우아하게 객체지향을 구사해놓은 linux kernel의 설계자들은 안하니만 못한 코딩을 하는 저급 코더로 전락할 수 밖에 없겠지요.

위에 있는 예제에서도 볼수 있듯이
C 에서 OOP 를 하는것은 불필요한 오버 헤드가 생깁니다.
C 언어 테크닉으로 그냥 알아만 두는것은 상관없지만 실제 코딩 하는것은
어렵고 좀더 긴 코드를 작성하게 됩니다.

Linux Kernel 개발자들도 커널 안에 C++ 코드를 넣을수 있었다면 C++ 로 개발 하였을 겁니다.
커널 안에 C++ 을 넣을수 없기 때문에 어쩔수 없이 이런 방식을 사용하게 된것이지요.

C++을 사용할수 없을때를 제외하고 C++ 을 사용가능할때
C 를 이용해서 OOP를 구현하는것은 잘못된 방법이란 생각이 듭니다.

죠커의 이미지

Anonymous wrote:
김경태 wrote:

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

정확하게 <결합>이란 의미를 설명하자면 프로그래머가 function과 그 대상인 데이타를 하나의 자료구조(그것이 structure든 class든 간에)로 인식될 수 있어야 한다는 말입니다.

실제로 class든 structure든 data와 method는 process 내부 공간안에 존재하기 때문에 process 내부 메모리에 같이 존재한다는 의미에서는 동일한 메모리에 위치한다고도 할 수 있습니다.

하나 그 동일한 메모리 공간에 위치한다는 말씀이 class에서 보여지는 것처럼 바로 인접한 메모리에 method와 data가 존재한다는 의미로 오해할 수 있는 소지가 충분히 있습니다.

데이타와 코드 모두 동일한 메모리 공간에 저장되어 있다고 하셨지만 제가 말하고자 했던 것은 실제 메모리상에서 활성화된 process 단위에서 데이타와 코드가 class에서 보여지는 것처럼 실제로 인접하고 있느냐 하는 점을 말씀드린 것입니다.

가령 structure 안의 pointer to function과 data들이 인접주소에 있을 수 있겠지만 pointer to function이 가리키고 있는 function과 data가 인접공간에 즉, 0001 0002 0003 0004 이런식으로 저장되어 있다면 그것은 사실이 아닙니다.

또한 일반적으로는 객체지향을 C++로 구현하는 것이 C로 구현하는 것보다 OO를 <더 쉽게!> code상에 구현하는 것은 맞지만 그렇다고 C로 구현한 OO가 모두 불완전하다고 단정하는 것도 또한 무리입니다.

그렇게 말씀하신다면 C로 매우 우아하게 객체지향을 구사해놓은 linux kernel의 설계자들은 안하니만 못한 코딩을 하는 저급 코더로 전락할 수 밖에 없겠지요.

위에 있는 예제에서도 볼수 있듯이
C 에서 OOP 를 하는것은 불필요한 오버 헤드가 생깁니다.
C 언어 테크닉으로 그냥 알아만 두는것은 상관없지만 실제 코딩 하는것은
어렵고 좀더 긴 코드를 작성하게 됩니다.

Linux Kernel 개발자들도 커널 안에 C++ 코드를 넣을수 있었다면 C++ 로 개발 하였을 겁니다.
커널 안에 C++ 을 넣을수 없기 때문에 어쩔수 없이 이런 방식을 사용하게 된것이지요.

C++을 사용할수 없을때를 제외하고 C++ 을 사용가능할때
C 를 이용해서 OOP를 구현하는것은 잘못된 방법이란 생각이 듭니다.

의문이 있습니다. C++의 객체지향은 Objective C에 비해 미흡합니다. 그럼 객체지향을 할 때는 C++을 쓰지 말아야 할까요? 아니면 객체지향에 더 적합한 언어로 바꾸어야 할까요?

C 언어로 시도한 객체지향이 C언어로 짠 다른 코드에 비해서 복잡도가 낮아지거나 추상화가 될 수 있다면 안할 이유가 없지 않느냐 생각합니다.

creativeidler의 이미지

C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

물론 저도 C언어라는 게 정해진 상황이라면 C안에서도 객체지향을 하는 게 낫다고 생각합니다만 사실 커널 레벨까지 내려가거나 임베디드에서도 아주 하드코어한 상황이 아닌 이상 C를 C++로 대체 못할 만한 경우는 많지 않습니다. 위에 손님의 글의 의도는 C++을 사용 가능할 때란 조건이 포함되어 있습니다. 이런 상황에서라면 굳이 C로 객체지향을 하는 것보다 C++ 쓰는 게 낫다는 것은 당연한 것 아닐까요?

pynoos의 이미지

moonzoo wrote:
C에서 구조체를 이용해서 클래스 흉내를 낼 수 있는지 궁금합니다.

멤버 변수와 멤버 함수가 있다고 할 경우에..

멤버 함수는 함수 포인터를 이용하면 가능하겠는데.

문제는. 멤버 함수에서 자신을 콜한 인스턴스의 멤버 변수에

어떻게 접근할 수 있을까? 입니다.

C++에서는 this 를 이용하지만 C에서는 어떤 테크닉이 있나여?

C 뿐 아니라, Perl에 구현된 개체지향의 개념도 잘 보면 C와 유사합니다.
오히려 Perl이 초기에 개체를 지원하지 않다가 구겨(?)들어가면서 고민하는 것들이
C의 개체지향적인 코딩과 다르지 않다는 것을 알 수 있습니다.

초창기 JavaScript에서 클래스 만드는 것도 생성자라는 것이
그저 함수안에서 this를 가지고 변수를 만드는 것으로 가능한 것도
처음엔 쉽지않은 개념이지만 생성자도 단지 함수에 불과하다는 생각을 심기에 충분하고요,

python에서도 클래스 지원은 self가 반드시 들어가야되 것으로 보면,
언어에서 고민하는 흔적이 대부분 비슷하다는 것을 알 수 있습니다.

이렇게 따지면, 본쉘 스크립트에서도 비슷한 것을 만들수 있겠거니! 하는 오버도 하고.
10년쯤된 마소의 안철수님의 개체지향적인 어셈블프로그래밍 기사도 비슷한 고민들입니다.

죠커의 이미지

creativeidler wrote:
C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

Objective C는 Smalltalk의 영향을 받은 순수 객체지향 언어로서 기초가 되는 객체가 존재하며 POD의 null을 쓰지 않고 nil을 반환하는 nil 객체를 씁니다. 그리고 3단계 메타클래스 개념을 가지고 있으며 메시지라는 개념으로 추상화 된 메소드 호출 기법을 가지고 있어 유연성있는 다형성을 보입니다. 비록 Smalltalk80 수준의 단계를 지원하지 못합니다만 Simulla67의 영향을 받아 그 정도 수준에 머무는 C++에 비해 더 객체지향적이라는 것은 자명합니다.

moonzoo의 이미지

creativeidler wrote:
C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

물론 저도 C언어라는 게 정해진 상황이라면 C안에서도 객체지향을 하는 게 낫다고 생각합니다만 사실 커널 레벨까지 내려가거나 임베디드에서도 아주 하드코어한 상황이 아닌 이상 C를 C++로 대체 못할 만한 경우는 많지 않습니다. 위에 손님의 글의 의도는 C++을 사용 가능할 때란 조건이 포함되어 있습니다. 이런 상황에서라면 굳이 C로 객체지향을 하는 것보다 C++ 쓰는 게 낫다는 것은 당연한 것 아닐까요?

제 생각은 좀 다릅니다.

객체지향은 하나의 패러다임입니다.

그것은 사용하는 언어에 종속되는 개념은 아니라고 봅니다.

언어에서 제공해주는 만큼만 "사고"가 한정되어야 할까요?

예를 들면 C++로 프로그래밍 한다고 해서

C++에서, 객체지향 이라는 패러다임에 대해

"편리하게 제공해주는 만큼만"

시스템을 구성하는 것은, 언어 종속적인 생각이라 생각합니다.

언어는 결국 "수단"에 불과하기 때문입니다.

익명 사용자의 이미지

moonzoo wrote:
C에서 구조체를 이용해서 클래스 흉내를 낼 수 있는지 궁금합니다.

멤버 변수와 멤버 함수가 있다고 할 경우에..

멤버 함수는 함수 포인터를 이용하면 가능하겠는데.

문제는. 멤버 함수에서 자신을 콜한 인스턴스의 멤버 변수에

어떻게 접근할 수 있을까? 입니다.

C++에서는 this 를 이용하지만 C에서는 어떤 테크닉이 있나여?

C++에서 내부적으로 함수의 첫번째 인자에 this를 넘겨주는 형식으로 멤버 함수를 구현합니다.

익명 사용자의 이미지

CN wrote:

C 언어로 시도한 객체지향이 C언어로 짠 다른 코드에 비해서 복잡도가 낮아지거나 추상화가 될 수 있다면 안할 이유가 없지 않느냐 생각합니다.

두번째 C 언어는 C++ 로 이해하고 이야기 하겠습니다...

C 언어로 구현한 객체지향이 C++ 로 구현한 객체지향보다
간단하거나 이해하기 쉽다면 않할 이유 당연히 없습니다...
그런데 그런 예제가 있습니까???
있다면 보여주세요.

반대의 경우는 제가 많이 보여드릴수 있는데요...

gimmesilver의 이미지

moonzoo wrote:
creativeidler wrote:
C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

물론 저도 C언어라는 게 정해진 상황이라면 C안에서도 객체지향을 하는 게 낫다고 생각합니다만 사실 커널 레벨까지 내려가거나 임베디드에서도 아주 하드코어한 상황이 아닌 이상 C를 C++로 대체 못할 만한 경우는 많지 않습니다. 위에 손님의 글의 의도는 C++을 사용 가능할 때란 조건이 포함되어 있습니다. 이런 상황에서라면 굳이 C로 객체지향을 하는 것보다 C++ 쓰는 게 낫다는 것은 당연한 것 아닐까요?

제 생각은 좀 다릅니다.

객체지향은 하나의 패러다임입니다.

그것은 사용하는 언어에 종속되는 개념은 아니라고 봅니다.

언어에서 제공해주는 만큼만 "사고"가 한정되어야 할까요?

예를 들면 C++로 프로그래밍 한다고 해서

C++에서, 객체지향 이라는 패러다임에 대해

"편리하게 제공해주는 만큼만"

시스템을 구성하는 것은, 언어 종속적인 생각이라 생각합니다.

언어는 결국 "수단"에 불과하기 때문입니다.

언어가 수단에 불과하다는 것은 언어의 힘을 너무 무시한 생각인 것 같습니다.
프로그래밍에서 중요한 것은 '사고'가 맞습니다. 그러나 그 '사고'를 표현해 주는 것은 '언어'이며 따라서 대개 '언어'에 의해 '사고'의 틀이 결정됩니다.
그 때문에 각 언어(굳이 프로그래밍 언어 뿐만이 아니라 우리가 사용하는 언어도 포함해서)가 가진 패러다임을 이해하는 것이 매우 중요합니다.
마찬가지로 객체 지향이 언어에 종속되는 것이 아니라고 하지만 실제 우리가 프로그래밍을 할 때 객체 지향 개념을 가지고 프로그래밍을 하기 위해서는 객체 지향 패러다임을 가진 언어를 가지고 프로그래밍 하는 것이 중요합니다.
객체 지향 패러다임 언어를 다뤄보지 못한 프로그래머가 객제 지향 설계 방식으로 프로그래밍을 한다는 것은 불가능하지는 않겠지만 무척 어려울 것입니다.
객체 지향 프로그래밍을 원한다면 해당 패러다임을 가진 언어를 사용하면 됩니다. 그리고 그런 객체 지향 패러다임의 언어를 가지고 프로그래밍 하는 것이 객체 지향을 이해하는데 가장 좋습니다.
굳이 C언어를 이용해서 그런 흉내를 낼 필요는 없지 않나 생각합니다.
많은 구루들이 다양한 패러다임을 가진 언어를 익혀보라고 조언하는 것은 바로 해당 언어가 그것을 익힌 사람의 사고에 가장 큰 영향을 주기 때문입니다.
말씀하신 의미는 이해하지만 문맥에 오해의 소지가 있어서 첨언했습니다.

------------------------
http://agbird.egloos.com

죠커의 이미지

Anonymous wrote:
CN wrote:

C 언어로 시도한 객체지향이 C언어로 짠 다른 코드에 비해서 복잡도가 낮아지거나 추상화가 될 수 있다면 안할 이유가 없지 않느냐 생각합니다.

두번째 C 언어는 C++ 로 이해하고 이야기 하겠습니다...

C 언어로 구현한 객체지향이 C++ 로 구현한 객체지향보다
간단하거나 이해하기 쉽다면 않할 이유 당연히 없습니다...
그런데 그런 예제가 있습니까???
있다면 보여주세요.

반대의 경우는 제가 많이 보여드릴수 있는데요...

C언어를 써서 객체지향적인 코드가 C언어로 짠 절차지향적인 코드보다 복잡도가 낮아지거나 추상화가 된다면이라는 의도로 말한 것 입니다.

죠커의 이미지

Agbird wrote:
moonzoo wrote:
creativeidler wrote:
C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

물론 저도 C언어라는 게 정해진 상황이라면 C안에서도 객체지향을 하는 게 낫다고 생각합니다만 사실 커널 레벨까지 내려가거나 임베디드에서도 아주 하드코어한 상황이 아닌 이상 C를 C++로 대체 못할 만한 경우는 많지 않습니다. 위에 손님의 글의 의도는 C++을 사용 가능할 때란 조건이 포함되어 있습니다. 이런 상황에서라면 굳이 C로 객체지향을 하는 것보다 C++ 쓰는 게 낫다는 것은 당연한 것 아닐까요?

제 생각은 좀 다릅니다.

객체지향은 하나의 패러다임입니다.

그것은 사용하는 언어에 종속되는 개념은 아니라고 봅니다.

언어에서 제공해주는 만큼만 "사고"가 한정되어야 할까요?

예를 들면 C++로 프로그래밍 한다고 해서

C++에서, 객체지향 이라는 패러다임에 대해

"편리하게 제공해주는 만큼만"

시스템을 구성하는 것은, 언어 종속적인 생각이라 생각합니다.

언어는 결국 "수단"에 불과하기 때문입니다.

언어가 수단에 불과하다는 것은 언어의 힘을 너무 무시한 생각인 것 같습니다.
프로그래밍에서 중요한 것은 '사고'가 맞습니다. 그러나 그 '사고'를 표현해 주는 것은 '언어'이며 따라서 대개 '언어'에 의해 '사고'의 틀이 결정됩니다.
그 때문에 각 언어(굳이 프로그래밍 언어 뿐만이 아니라 우리가 사용하는 언어도 포함해서)가 가진 패러다임을 이해하는 것이 매우 중요합니다.
마찬가지로 객체 지향이 언어에 종속되는 것이 아니라고 하지만 실제 우리가 프로그래밍을 할 때 객체 지향 개념을 가지고 프로그래밍을 하기 위해서는 객체 지향 패러다임을 가진 언어를 가지고 프로그래밍 하는 것이 중요합니다.
객체 지향 패러다임 언어를 다뤄보지 못한 프로그래머가 객제 지향 설계 방식으로 프로그래밍을 한다는 것은 불가능하지는 않겠지만 무척 어려울 것입니다.
객체 지향 프로그래밍을 원한다면 해당 패러다임을 가진 언어를 사용하면 됩니다. 그리고 그런 객체 지향 패러다임의 언어를 가지고 프로그래밍 하는 것이 객체 지향을 이해하는데 가장 좋습니다.
굳이 C언어를 이용해서 그런 흉내를 낼 필요는 없지 않나 생각합니다.
많은 구루들이 다양한 패러다임을 가진 언어를 익혀보라고 조언하는 것은 바로 해당 언어가 그것을 익힌 사람의 사고에 가장 큰 영향을 주기 때문입니다.
말씀하신 의미는 이해하지만 문맥에 오해의 소지가 있어서 첨언했습니다.

추구할 패러다임과 현실의 언어 간의 갭이 있기 때문에 언어를 도구로 사용할 수 밖에 없을 것 같습니다. 객체지향 프로그래밍을 해야한다고 Smalltalk로 함수형 프로그래밍을 하고자 Haskel을 메타 프로그래밍을 할려고 Lisp을 "선택할 수 있는 권한"을 가진 사람 아니라면 추구하는 패러다임과 선택하는 언어 간의 갭은 어쩔 것 같습니다.

익명 사용자의 이미지

CN wrote:

C언어를 써서 객체지향적인 코드가 C언어로 짠 절차지향적인 코드보다 복잡도가 낮아지거나 추상화가 된다면이라는 의도로 말한 것 입니다.

제가 잘못 이해했군요~~^^;;;
이제 올바른 답변을 달겠습니다.

어떤 시스템을 설계 하는데 객체지향적인 관전이 어울린다면
당연히 객체지향적으로 설계하고 구현해야합니다.

그런데 꼭 객체지향으로 구현하기 어려운 도구로 구현해야될 필요가 있나요???

제 경험상 C 언어를 써서 객체지향을 사용한 코드보다
C++ 에서 객체지향을 사용한 코드가 항상(!)
복잡도도 낮아지고 추상화도 더 잘 된다고 생각합니다.

위의 예 같은 경우 왜 C++은 고려 대상이 아닌가요??

익명 사용자의 이미지

추가적으로

"가능하다" 란것과
"효율적이다" 란것과는

많은 차이가 있습니다.

C 에서 객체지향은 가능할 뿐이지 비효율적입니다.
그런데 여기 글쓰신 분들중에 효율적이다란 의미로 쓰신 분들이
몇분 계셔서 쓸데없이 글을 올렸습니다.

IsExist의 이미지

개발 방법론으로 인한 비용 상쇄 보다는 개발 인력의 수준에 따른
비용 감쇄가 오히려 더 큰 위험 요소죠.

어떤 개발 방법론을 따르냐 보다는 개발시 어떻게 잘 협력이 이루어지고
개발자들 사이에 통신이 잘되냐가 더 큰 요소인거 같습니다.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

죠커의 이미지

Anonymous wrote:
CN wrote:

C언어를 써서 객체지향적인 코드가 C언어로 짠 절차지향적인 코드보다 복잡도가 낮아지거나 추상화가 된다면이라는 의도로 말한 것 입니다.

제가 잘못 이해했군요~~^^;;;
이제 올바른 답변을 달겠습니다.

어떤 시스템을 설계 하는데 객체지향적인 관전이 어울린다면
당연히 객체지향적으로 설계하고 구현해야합니다.

그런데 꼭 객체지향으로 구현하기 어려운 도구로 구현해야될 필요가 있나요???

제 경험상 C 언어를 써서 객체지향을 사용한 코드보다
C++ 에서 객체지향을 사용한 코드가 항상(!)
복잡도도 낮아지고 추상화도 더 잘 된다고 생각합니다.

위의 예 같은 경우 왜 C++은 고려 대상이 아닌가요??

객체지향을 사용하기 위해 C++을 포기하고 Smalltalk나 Obejctive C를 사용하는 것이 옳은 일일까요?

옳을 수도 있고 아닐 수도 있습니다.

C에서 객체지향을 사용하는 것과 C++을 사용하는 것도 마찬가지의 문제라고 봅니다.

어떤 것에 더 비중을 맞추느냐와 선호의 문제에 따라 선택이 달라지겠지요.

Quote:
추가적으로

"가능하다" 란것과
"효율적이다" 란것과는

많은 차이가 있습니다.

C 에서 객체지향은 가능할 뿐이지 비효율적입니다.
그런데 여기 글쓰신 분들중에 효율적이다란 의미로 쓰신 분들이
몇분 계셔서 쓸데없이 글을 올렸습니다.

이 쓰래드에서 C에서 객체지향을 하는 것이 C++에서 객체지향을 하는 것에 비해 효율적이다고 이야기를 하시는 분은 없는 것 같습니다.

익명 사용자의 이미지

CN wrote:

객체지향을 사용하기 위해 C++을 포기하고 Smalltalk나 Obejctive C를 사용하는 것이 옳은 일일까요?

옳을 수도 있고 아닐 수도 있습니다.

C에서 객체지향을 사용하는 것과 C++을 사용하는 것도 마찬가지의 문제라고 봅니다.

어떤 것에 더 비중을 맞추느냐와 선호의 문제에 따라 선택이 달라지겠지요.


똑같은 이야기만 할 꺼 같은 느낌이 들어서 간단히 이야기 하겠습니다.

핀셋으로 밥을 먹을수 있습니다. 하지만 밥을 먹을때 핀셋을 사용할 이유는 없습니다.
나무 가지는 식칼로 벨수 있습니다. 하지만 나무를 베기위해 식칼을 사용할 이유는 없습니다.

객체지향을 사용하기 위해 C++, Java, C#, Smalltalk, Objective C 등은
고려 대상이 될수 있습니다. 하지만 C 가 고려대상이 될 이유는 없습니다.
여기까지가 저의 생각입니다.

그래도 C 가지고 한다면 서로 생각이 다른거니 어쩔수 없지요~

creativeidler의 이미지

흠. 솔직히 moonzoo님의 글은 무슨 말인지 잘 모르겠습니다. C++을 쓸 수 있는 상황에서 굳이 C로 객체지향을 할 필요가 있냐는 주장에 대해 언어가 도구라는 주장이 어떤 식으로 반론으로 기능할 수 있는지 잘 모르겠군요. 오히려 제 주장을 지지하는 것 같기도 하고-_-

Quote:
Objective C는 Smalltalk의 영향을 받은 순수 객체지향 언어로서 기초가 되는 객체가 존재하며 POD의 null을 쓰지 않고 nil을 반환하는 nil 객체를 씁니다. 그리고 3단계 메타클래스 개념을 가지고 있으며 메시지라는 개념으로 추상화 된 메소드 호출 기법을 가지고 있어 유연성있는 다형성을 보입니다. 비록 Smalltalk80 수준의 단계를 지원하지 못합니다만 Simulla67의 영향을 받아 그 정도 수준에 머무는 C++에 비해 더 객체지향적이라는 것은 자명합니다.

기초 객체의 존재가 왜 더 객체지향적인지는 잘 모르겠군요. nil 객체의 존재도 java의 경우 null이 객체가 아니지만 그것이 비객체지향적 요소로 지적되고 있진 않습니다. 어차피 nil이 NullObject 패턴을 쉽게 해주는 것도 아니고요. C++의 다형성은 어떤 의미에서 유연성이 떨어진다고 생각하시는지요?

가능하다면 좀 구체적인 사례를 들어서 비교해주시면 감사하겠습니다. 어떤 코드를 두고 C++은 이런데 Objective C는 이렇잖아, 그러니까 이게 더 객체지향적이지..이런 식이면 좋을 것 같네요. 전 솔직히 그런 코드의 예를 보여주기란 굉장히 힘들 꺼라고 봅니다. 이미 C++은 객체지향적인 개념을 구현하기에 부족함이 없다는 것이 긴 세월을 통해 검증이 되었으니까요. C의 한계를 물려 받은 불편함만 아니라면 객체지향 언어로서 다른 언어에 별달리 뒤질 것이 없다고 봅니다.

gimmesilver의 이미지

CN wrote:
Agbird wrote:
moonzoo wrote:
creativeidler wrote:
C++의 객체지향이 Objective C에 비해 미흡하다는 건 글쎄요. Objective C의 장점은 C의 superset이라는 것 아닌가요? 객체지향에 관해서라면 C++보다 낫다고 할만한 요소가 있는지 의문입니다.

물론 저도 C언어라는 게 정해진 상황이라면 C안에서도 객체지향을 하는 게 낫다고 생각합니다만 사실 커널 레벨까지 내려가거나 임베디드에서도 아주 하드코어한 상황이 아닌 이상 C를 C++로 대체 못할 만한 경우는 많지 않습니다. 위에 손님의 글의 의도는 C++을 사용 가능할 때란 조건이 포함되어 있습니다. 이런 상황에서라면 굳이 C로 객체지향을 하는 것보다 C++ 쓰는 게 낫다는 것은 당연한 것 아닐까요?

제 생각은 좀 다릅니다.

객체지향은 하나의 패러다임입니다.

그것은 사용하는 언어에 종속되는 개념은 아니라고 봅니다.

언어에서 제공해주는 만큼만 "사고"가 한정되어야 할까요?

예를 들면 C++로 프로그래밍 한다고 해서

C++에서, 객체지향 이라는 패러다임에 대해

"편리하게 제공해주는 만큼만"

시스템을 구성하는 것은, 언어 종속적인 생각이라 생각합니다.

언어는 결국 "수단"에 불과하기 때문입니다.

언어가 수단에 불과하다는 것은 언어의 힘을 너무 무시한 생각인 것 같습니다.
프로그래밍에서 중요한 것은 '사고'가 맞습니다. 그러나 그 '사고'를 표현해 주는 것은 '언어'이며 따라서 대개 '언어'에 의해 '사고'의 틀이 결정됩니다.
그 때문에 각 언어(굳이 프로그래밍 언어 뿐만이 아니라 우리가 사용하는 언어도 포함해서)가 가진 패러다임을 이해하는 것이 매우 중요합니다.
마찬가지로 객체 지향이 언어에 종속되는 것이 아니라고 하지만 실제 우리가 프로그래밍을 할 때 객체 지향 개념을 가지고 프로그래밍을 하기 위해서는 객체 지향 패러다임을 가진 언어를 가지고 프로그래밍 하는 것이 중요합니다.
객체 지향 패러다임 언어를 다뤄보지 못한 프로그래머가 객제 지향 설계 방식으로 프로그래밍을 한다는 것은 불가능하지는 않겠지만 무척 어려울 것입니다.
객체 지향 프로그래밍을 원한다면 해당 패러다임을 가진 언어를 사용하면 됩니다. 그리고 그런 객체 지향 패러다임의 언어를 가지고 프로그래밍 하는 것이 객체 지향을 이해하는데 가장 좋습니다.
굳이 C언어를 이용해서 그런 흉내를 낼 필요는 없지 않나 생각합니다.
많은 구루들이 다양한 패러다임을 가진 언어를 익혀보라고 조언하는 것은 바로 해당 언어가 그것을 익힌 사람의 사고에 가장 큰 영향을 주기 때문입니다.
말씀하신 의미는 이해하지만 문맥에 오해의 소지가 있어서 첨언했습니다.

추구할 패러다임과 현실의 언어 간의 갭이 있기 때문에 언어를 도구로 사용할 수 밖에 없을 것 같습니다. 객체지향 프로그래밍을 해야한다고 Smalltalk로 함수형 프로그래밍을 하고자 Haskel을 메타 프로그래밍을 할려고 Lisp을 "선택할 수 있는 권한"을 가진 사람 아니라면 추구하는 패러다임과 선택하는 언어 간의 갭은 어쩔 것 같습니다.

우리가 프로그래밍을 하는 것은 '어떤 패러다임으로 구현'하는 것이 아니라 '어떤 문제를 구현하기 위해 어떤 패러다임을 이용'할 것인가 입니다.
즉, 문제 해결법을 찾고 그 해결법을 구현하기 위한 방법으로 객체 지향 패러다임을 이용할 수도 있고 함수형 패러다임을 이용할 수도 있는 것입니다.
제가 말씀드리고 싶었던 것은 바로 그런 패러다임의 선택이 자신이 배운 언어에 영향을 가장 크게 받는 다는 점입니다.
객체 지향 언어를 익히지 못한 사람이 어떻게 객체 지향 패러다임을 가지고 프로그래밍을 할 수 있겠습니까? 함수형 패러다임을 접해보지 못한 사람이 어떻게 함수형 언어의 패러다임을 가지고 문제 해결법을 구현하겠습니까?
최초 질문하신 분도 기존에 객체 지향 언어를 접했었기 때문에 C를 이용해서 클래스를 구현해 보고자 하는 생각을 하신 것입니다. 그렇지 않았다면 그런 생각을 하기가 매우 힘들 것입니다.
언어는 사고를 구체화하는 도구일 뿐아니라 사고의 틀 자체이기도 합니다.
제가 생각하기에 C를 이용해서 객체지향을 흉내낸다는 것은 단지 언어적 유희에 불과합니다. 객체 지향 패러다임을 이해하는 데 도움이 전혀 되지 않을 뿐더러 마치 우리말, 우리글을 가지고 어설픈 번역체 말투를 사용하는 것과 같이 어색할 뿐입니다.

------------------------
http://agbird.egloos.com

익명 사용자의 이미지

1. 어떤 문제 해결에는 적합한 도구와 방법이 존재하기 마련이며 이러한 선택의 범위내에서 문제를 해결해 나가는것이 그렇지 않을 때보다 훨씬 효율적이다.

2. but, 1을 염두에 둔다고 하더라도 현실적인 여러 제약들(특정 언어 컴파일러를 회사 사정상 구할 수 없다거나 또는 프로그래머가 특정 언어에만 종속되어 있는 상황에서 신규 프로그래머를 더 채용할 수 없는 동시에 현재의 프로그래머를 해직시킬수도 없을 때 등)때문에 적합한 방법내지는 도구를 사용할 수 없는 경우가 생긴다. 그리고 이런 경우에 한해서만 어느정도의 비효율성을 감수하고 문제해결에 다소 부적절한 방법과 도구를 사용하는것이 허용된다.

이렇게 하면 정리가 됩니까?

죠커의 이미지

creativeidler wrote:
기초 객체의 존재가 왜 더 객체지향적인지는 잘 모르겠군요. nil 객체의 존재도 java의 경우 null이 객체가 아니지만 그것이 비객체지향적 요소로 지적되고 있진 않습니다. 어차피 nil이 NullObject 패턴을 쉽게 해주는 것도 아니고요. C++의 다형성은 어떤 의미에서 유연성이 떨어진다고 생각하시는지요?

아래의 예제를 봅시다.

myRect->primaryColor()->getRed();

C++의 코드입니다. myRect->primaryColor()는 Color 객체의 포인터를 반환한다고 합시다. 여기에서 primaryColor()가 객체의 포인트가 아닌 null을 반환했다면 어떻게 될까요? C++의 경우에는 이런 부분에 대해서 의식적으로 절차지향적인 방법으로 잡아주거나 언급하신 NullObject 패턴을 사용해야만 합니다. 반면에 Objective C에서는

[[myRect primaryColor] red];

이 코드가 문제를 일으킬 가능성은 없습니다. myRect 객체에서 primaryColor를 호출하면 어떤 형태이든 객체를 반환할 것입니다. Objective C는 C와 같이 암묵적으로 int를 반환하지 않고 (implicit int) 모든 객체를 가리킬 수 있는 id를 반환합니다. 그리고 호출이 실패했을 경우에는 POD인 null이 아닌 객체 nil을 반환할 것입니다. 이제 red라는 메시지를 처리해야 할 것입니다. Objective C에서 메시지를 처리할 때는 Smalltalk 처럼 상속과 서브타입 모두를 다룹니다. 간단히 말하면 red라는 메소드가 있고 인자의 "명칭":이 같다면 무조건 실행가능합니다. (위의 소스에는 두번의 메시지 모두 인자가 없습니다.) 그래서 결국 nil 객체의 red 메소드를 다루는 메시지로서 실행이 될 것입니다. 그런데 nil 객체의 red 메소드가 없으니 문제를 일으키겠군요? 하지만 아무런 문제가 없습니다. nil 객체를 향하는 모든 메시지는 nil 객체를 반환하도록 "메시지가 규정" 되어 있습니다. Objective C의 메시지는 C++의 메소드와는 달리 물리적인 레이어에서 떨어져 있습니다. 개발자는 primaryColor 메시지가 성공적으로 수행이 되었는지만 관심을 가지면 됩니다. 성공하지 못했다면 nil 객체를 가지고 있을 것입니다. nil 객체를 확인하는 방법도 간단합니다. Color를 받았다고 가정하고 객체로 할 일을 수행하면 nil이 전파될 것입니다. 서브타입과 개념적인 메시지 호출, nil 객체는 C++의 객체 구조보다 더 유연하며 더 강력한 다형성을 보장합니다.

보통은 토론의 행방은 알 수 없지만 앞으로 토론이 계속되면 어떤 이야기를 나누게 될지는 알 수 있을 것 같습니다. 캡슐화가 추가된 60년대생 Simula의 후예와 70년대생 Smalltalk의 후예에 대한 이야기겠지요.

creativeidler의 이미지

글쎄요. 그게 장점인지는 잘 모르겠습니다. 만약 myRect가 null이어도 좋은 상황이라면 문제를 일으키지 않고 그냥 지나가는 것이 좋겠습니다만 myRect가 null이라는 것이 다른 코드의 버그로 인해 유발된 것이라면요? 그러면 Objective C에서처럼 조용히 지나가버리면 버그를 은폐하는 코드가 되버립니다.

java의 경우에도 많은 자바 초보 개발자들이 NullPointerException이 두려워서 이게 발생 안하게 하려고 별 짓을 다합니다. 예를 들면 이런 거죠.

if ("OK".equals(inputStr)) return true;
return false;

혹은

if (inputStr != null && inputStr.equals("OK")) return true;
return false;

이게 inputStr이 OK일 때 동작, NO이거나 null일 때의 동작 두 가지로 나뉘어진다면 문제 없는 코드입니다. 그러나 inputStr이 OK일 때, NO일 때만 동작이 정의되고 null은 들어와서는 안되는 값이라면 저런 코드는 굉장히 찾기 어려운 버그를 만듭니다. 그럴 땐 다음과 같은 코드가 바람직하죠.

if (inputStr.equals("OK")) return true;
return false;

이렇게 하면 null이 들어오면 안될 때 null이 들어오면 바로 NullPointerException이 발생합니다. 프로그래머가 알아차릴 수 있는 것이죠. OOP에서 대개 객체가 null이라는 것은 무언가 비정상적인 상황이라는 의미이고 이럴 때는 예외가 발생해서 예외 처리 루틴으로 가야합니다. 문제가 있으면 빨리 그 문제점이 노출되게 만드는 코드가 좋은 코드 아니겠습니까.

물론 조용히 지나가게 하고 싶을 때도 있을 것입니다. 그럴 때 NullObject 패턴을 쓰면 되는 것이죠. 하지만 프로그래머가 조용히 지나가고 싶다는 것을 명시하지 않았는데도 조용히 지나간다면 별로 좋은 방식이 아닌 것 같습니다.

익명 사용자의 이미지

Anonymous wrote:
CN wrote:

객체지향을 사용하기 위해 C++을 포기하고 Smalltalk나 Obejctive C를 사용하는 것이 옳은 일일까요?

옳을 수도 있고 아닐 수도 있습니다.

C에서 객체지향을 사용하는 것과 C++을 사용하는 것도 마찬가지의 문제라고 봅니다.

어떤 것에 더 비중을 맞추느냐와 선호의 문제에 따라 선택이 달라지겠지요.


똑같은 이야기만 할 꺼 같은 느낌이 들어서 간단히 이야기 하겠습니다.

핀셋으로 밥을 먹을수 있습니다. 하지만 밥을 먹을때 핀셋을 사용할 이유는 없습니다.
나무 가지는 식칼로 벨수 있습니다. 하지만 나무를 베기위해 식칼을 사용할 이유는 없습니다.

객체지향을 사용하기 위해 C++, Java, C#, Smalltalk, Objective C 등은
고려 대상이 될수 있습니다. 하지만 C 가 고려대상이 될 이유는 없습니다.
여기까지가 저의 생각입니다.

그래도 C 가지고 한다면 서로 생각이 다른거니 어쩔수 없지요~

C 도 고려 대상이 될수 있습니다.

http://bbs.kldp.org/viewtopic.php?t=33892&highlight=%BD%BA%C6%C4%B0%D4%C6%BC

적절한 예가 될지는 모르겠군요.

익명 사용자의 이미지

Anonymous wrote:
CN wrote:

객체지향을 사용하기 위해 C++을 포기하고 Smalltalk나 Obejctive C를 사용하는 것이 옳은 일일까요?

옳을 수도 있고 아닐 수도 있습니다.

C에서 객체지향을 사용하는 것과 C++을 사용하는 것도 마찬가지의 문제라고 봅니다.

어떤 것에 더 비중을 맞추느냐와 선호의 문제에 따라 선택이 달라지겠지요.


똑같은 이야기만 할 꺼 같은 느낌이 들어서 간단히 이야기 하겠습니다.

핀셋으로 밥을 먹을수 있습니다. 하지만 밥을 먹을때 핀셋을 사용할 이유는 없습니다.
나무 가지는 식칼로 벨수 있습니다. 하지만 나무를 베기위해 식칼을 사용할 이유는 없습니다.

객체지향을 사용하기 위해 C++, Java, C#, Smalltalk, Objective C 등은
고려 대상이 될수 있습니다. 하지만 C 가 고려대상이 될 이유는 없습니다.
여기까지가 저의 생각입니다.

그래도 C 가지고 한다면 서로 생각이 다른거니 어쩔수 없지요~

C 도 고려 대상이 될수 있습니다.

http://bbs.kldp.org/viewtopic.php?t=33892&highlight=%BD%BA%C6%C4%B0%D4%C6%BC

적절한 예가 될지는 모르겠군요.

김경태의 이미지

이렇게 말씀하시는 분이 계시군요. 과연 그럴까요?

우리가 C++라는 언어가 일반화 된 지금에 와서는 C++사용경험을 통하여 C로 객체지향의 장점을 구현할 수 없을까 하는 고민을 하게 된다는 점에서 일반적으로는 맞는 말일수 있습니다.

하지만 반드시 그런것만은 아닙니다.

가령 assembly에 익숙한 사람에게 있어서는 모든 가치판단기준이 assembly이기 때문에 C program을 보면서도 "이건 assembly로 구현하면 어떻게 구현될까?"라는 자연스런 질문을 던지게 됩니다.

그래서 그러한 고민의 끝에 결국 C program을 보고서 그와 상응한 기능을 assembly로 구현해보고 그 장점을 취하게 됩니다.

이러한 경향은 assembly programmer가 반드시 구조적 프로그램 기법에 익숙하거나 C를 많이 사용해서 얻어진 결과물이 아니라 단지 사람이란 존재가 무언가 새로운 것을 익혔을 때 늘 과거 자신이 지니고 있던 지식의 틀에 비교하는 본능적인 무엇이 있기 때문입니다.

마찬가지로 C에 익숙한 사람은 C++ 코드를 보면서도 과연 C로는 이것이 어떻게 구현되어 있을까? 라는 자연스러운 질문을 던지게 됩니다.

그런 자연스런 질문의 결과로 C++의 class는 structure로 매핑되고 method는 pointer to function으로 상속은 pointer to structure로 매핑된다는 사실을 추론하게 됩니다.

위의 assembly programmer의 예와 마찬가지로 이러한 경향은 C programmer가 반드시 OO 프로그램 기법에 익숙하거나 C++를 많이 사용해서 얻어진 결과물이 아니라 단지 사람이란 존재가 무언가 새로운 것을 익혔을 때 늘 과거 자신이 지니고 있던 지식의 틀에 비교하는 본능적인 무엇이 있기 때문입니다.

C++에 익숙해져서 혹은 C++에서 OO개념을 철저히 학습한 결과로 C progammer들이 C++을 C식으로 바라본다는 것은 이러한 의미에서는 자연스런 인간의 본능적 성향을 망각한 성급한 단정이 아닐까 생각해 봅니다.

그리고....

C++창시자는 처음에 객체지향을 C로 구현하려고 노력했고 그러한 노력의 결과 그는 성공하였으며 그결과물이 바로 C++이란 언어입니다.

이러한 과정은 최초 C++이 C로의 precompile과정을 거쳤다는 것만 봐도 확연히 알수 있는 사실입니다.

만약 모든 사람이 C++을 배웠기 때문에 C로 OO를 구현하려고 시도한다는 말이 사실이라면 지금의 C++은 생길 수도 없었다는 점을 말씀드리고 싶습니다.

다른 사람도 아닌 C++ 창시자 자체가 원래는 C로 객체지향을 구현하였고 이를 바탕으로해서 C++이란 언어가 탄생하게 되었다는 역사적인 사례는 C++을 배우지도 않고 C를 통해서 객체지향을 생각할 수 있다는 가장 명확한 일예가 아닐 수 없습니다.

죠커의 이미지

creativeidler wrote:
if (inputStr.equals("OK")) return true;
return false;

이렇게 하면 null이 들어오면 안될 때 null이 들어오면 바로 NullPointerException이 발생합니다. 프로그래머가 알아차릴 수 있는 것이죠. OOP에서 대개 객체가 null이라는 것은 무언가 비정상적인 상황이라는 의미이고 이럴 때는 예외가 발생해서 예외 처리 루틴으로 가야합니다. 문제가 있으면 빨리 그 문제점이 노출되게 만드는 코드가 좋은 코드 아니겠습니까.

물론 조용히 지나가게 하고 싶을 때도 있을 것입니다. 그럴 때 NullObject 패턴을 쓰면 되는 것이죠. 하지만 프로그래머가 조용히 지나가고 싶다는 것을 명시하지 않았는데도 조용히 지나간다면 별로 좋은 방식이 아닌 것 같습니다.

Objective C에서 nil은 객체의 하나에 불과하고 Objective C의 메소드의 리턴은 디폴트가 객체입니다. 굳이 equals를 bool형으로 반환 값을 규정했다면 에러를 내고 예외를 낼 것이니 문제가 안됩니다. 그리고 디폴트인 객체를 이용했다면 호출자는 nil이 들어온 것을 쉽게 앍아내고 처리해낼 수 있을 것입니다. 더구나 한 발 앞서 equals라는 메시지를 처리할 수 있느냐를 미리 판단하고 적합한 객체에게 전달할 수 있습니다. (일컨데 예외처리를 담당하는 객체도 가능하겠지요.)

그리고 몇가지 더 이야기를 꺼낼려고 합니다. Objective C에는 카테고리와 프로토콜이라는 개념이 지원되고 있습니다. 프로토콜이란 개념은 자바와 인터페이스와 유사한 개념인데 Objective C 클래스 전체 혹은 일부에 인터페이스를 강제할 수 있습니다. 이런 행위 패턴은 C++에서는 힘든 방법입니다. 거기에 더 나아가 카테고리라는 개념을 통해서 클래스를 수평적 확장이 가능합니다. 이 수평적 확장은 원본 클래스의 소스코드가 존재하지 않을때도 가능합니다. Simula 형태의 상속을 이용한 C++의 경우 상속을 이용한 수직적 확장만 가능하며 원본의 소스코드가 없을 경우 확장이 힘들어 집니다. 카테고리 기능은 클래스의 메소드를 추가 혹은 수정하여 새로운 클래스 명칭을 붙이는 기능입니다.

더구나 다형성 면에서는 함수의 전달인자에 의한 함수 테이블 선택 형태인 C++보다는 훨씬 발전된 형태를 가지고 있습니다. Objective C는 클래스의 정보를 담기 위한 메타 클래스가 존재하며 루트 클래스는 보다 세밀한 수준의 메모리 관리, 객체 관리, 타입 관리 등의 정보를 런타임으로 제공해주고 이 루트 클래스는 (Java의 Object와는 달리) 유저가 사용 여부를 선택할 수 있습니다. 메타 클래스와 루트 클래스의 도움으로 Objective의 다형성은 보다 넒은 범위에서 적용이 가능합니다. Objective C의 메시지는 상속관계를 통들어서 관련 객체 모두에게 전달될 수도 있으며 단일 객체에만 전달 될 수도 있고 전달될 객체를 선택할 수도 있습니다. 이 메시지로 인한 호출은 상속관계에만 좌우되지 않고 동일한 메소드 명칭과 인자 명칭을 가진 메소드도 호출이 가능합니다. C++은 스몰토크나 Objective C만큼 메시지를 "메시지"답게 처리할 수 없습니다.

gimmesilver의 이미지

김경태 wrote:
이렇게 말씀하시는 분이 계시군요. 과연 그럴까요?

우리가 C++라는 언어가 일반화 된 지금에 와서는 C++사용경험을 통하여 C로 객체지향의 장점을 구현할 수 없을까 하는 고민을 하게 된다는 점에서 일반적으로는 맞는 말일수 있습니다.

하지만 반드시 그런것만은 아닙니다.

가령 assembly에 익숙한 사람에게 있어서는 모든 가치판단기준이 assembly이기 때문에 C program을 보면서도 "이건 assembly로 구현하면 어떻게 구현될까?"라는 자연스런 질문을 던지게 됩니다.

그래서 그러한 고민의 끝에 결국 C program을 보고서 그와 상응한 기능을 assembly로 구현해보고 그 장점을 취하게 됩니다.

이러한 경향은 assembly programmer가 반드시 구조적 프로그램 기법에 익숙하거나 C를 많이 사용해서 얻어진 결과물이 아니라 단지 사람이란 존재가 무언가 새로운 것을 익혔을 때 늘 과거 자신이 지니고 있던 지식의 틀에 비교하는 본능적인 무엇이 있기 때문입니다.

마찬가지로 C에 익숙한 사람은 C++ 코드를 보면서도 과연 C로는 이것이 어떻게 구현되어 있을까? 라는 자연스러운 질문을 던지게 됩니다.

그런 자연스런 질문의 결과로 C++의 class는 structure로 매핑되고 method는 pointer to function으로 상속은 pointer to structure로 매핑된다는 사실을 추론하게 됩니다.

위의 assembly programmer의 예와 마찬가지로 이러한 경향은 C programmer가 반드시 OO 프로그램 기법에 익숙하거나 C++를 많이 사용해서 얻어진 결과물이 아니라 단지 사람이란 존재가 무언가 새로운 것을 익혔을 때 늘 과거 자신이 지니고 있던 지식의 틀에 비교하는 본능적인 무엇이 있기 때문입니다.

C++에 익숙해져서 혹은 C++에서 OO개념을 철저히 학습한 결과로 C progammer들이 C++을 C식으로 바라본다는 것은 이러한 의미에서는 자연스런 인간의 본능적 성향을 망각한 성급한 단정이 아닐까 생각해 봅니다.

그리고....

C++창시자는 처음에 객체지향을 C로 구현하려고 노력했고 그러한 노력의 결과 그는 성공하였으며 그결과물이 바로 C++이란 언어입니다.

이러한 과정은 최초 C++이 C로의 precompile과정을 거쳤다는 것만 봐도 확연히 알수 있는 사실입니다.

만약 모든 사람이 C++을 배웠기 때문에 C로 OO를 구현하려고 시도한다는 말이 사실이라면 지금의 C++은 생길 수도 없었다는 점을 말씀드리고 싶습니다.

다른 사람도 아닌 C++ 창시자 자체가 원래는 C로 객체지향을 구현하였고 이를 바탕으로해서 C++이란 언어가 탄생하게 되었다는 역사적인 사례는 C++을 배우지도 않고 C를 통해서 객체지향을 생각할 수 있다는 가장 명확한 일예가 아닐 수 없습니다.

뭔가 오해하셨군요. 제 주장의 요지는 언어는 단순한 도구가 아니라 사고의 틀을 제공한다는 것입니다.

예를 드신 것 처럼 C프로그래머가 C++을 접했을 때 C에 적용해 보려고 하는 것은 C++라는 언어를 통해서 객체 지향 개념을 접했기 때문에 가능한 것입니다.
게다가 class는 structure로 매핑되고 method는 pointer to function으로 매필된다는 식의 사고 방식을 같는다는 것 자체가 이미 C언어의 패러다임에 영향을 받았다는 것을 뜻합니다. 이것 모두 언어는 단순한 도구가 아니라는 사실을 의미합니다.
즉, C프로그래머가 C++를 학습한 결과로 C++를 C식으로 바라보는 것이 아니라 반대로 C에 익숙하기 때문에 C++를 C식으로 바라보는 것입니다. C++에 익숙하다면 굳이 그런 비교를 할 필요가 없습니다. 자연스럽게 패러다임이 몸에 배어 있기 때문입니다.
그리고 C++가 C로 구현된 역사적 사실은 님의 주장에 적절한 예가 못된다고 생각합니다. C++가 객체지향 언어라고 해서 C++언어를 구현하는 작업 자체가 객체 지향 패러다임을 가질 필요는 없기 때문입니다.
프로그래밍은 '문제를 해결하는 방법(알고리즘)' 과 '해결 방법을 구현하는 방법(패러다임)'으로 나뉩니다. 그리고 언어는 후자에 영향을 끼칩니다.
C++는 '객체 지향 프로그래밍이 가능한 언어를 구현하는 방법'에 대한 결과물이고 그 결과물을 구현하기 위한 방법으로 C를 선택한 것입니다.
다시 말하면 '객제 지향 프로그래밍 방법(언어)'를 구현하기 위한 방법이 C언어였지, '객체 지향 프로그래밍 방법'이 C는 아니였다는 말씀입니다.
게다가 객체 지향 패러다임은 C++가 세상에 나오기 십 수년 전에 이미 있었던 개념이고 simula와 같은 객체 지향 언어가 이미 세상에 존재하던 시기입니다.
물론 최초에 객체 지향 패러다임은 어떻게 생겨났는가에 대한 의문이 들 수 있습니다. 그러나 그건 어느 순간 불쑥 떠오는 생각도 아닐 것이고 기존 패러다임을 조금씩 확장하는 과정에서 나왔을 것입니다.
어쨌든 언어의 패러다임과 그 언어를 구현한 방법과는 별개라는 점을 말씀드리고 싶습니다.

------------------------
http://agbird.egloos.com

죠커의 이미지

Agbird wrote:
뭔가 오해하셨군요. 제 주장의 요지는 언어는 단순한 도구가 아니라 사고의 틀을 제공한다는 것입니다.

최초의 Simula는 Algol에 대한 wrapper에 불과했습니다. Simula가 개념적으로 미숙한 것은 사실이지만 완전히 지원하지 못했던 것은 캡슐화에 불과합니다. Simula팀에게 Algol은 도구일까요? 사고의 틀일까요? 그들에게 도구이자 사고의 틀일 수도 있고 둘다 아닐지도 모릅니다.

익명 사용자의 이미지

객체지향을 올바르게 사용하기 위해선 생각을 바꿔야 합니다.

저는 기존 방법에 비해 완전 다른 생각을 해야 객체지향의 장점을 이해할수 있었습니다.
(갠적으론 C++도 싫습니다....C++ 땜시 생각을 바꾸는데 오래걸렸거든요)

C 언어로 객체지향 흉내낼수 있지만 결코 생각을 바꿀순 없습니다.

저 개인적으론 UML 과 같은 모델링 언어가 효율적으로 사용되지
않는 이유는 사람들이 객체지향에 대해서 확실하기 이해하질 못하기 때문이라고 생각합니다.

Java 나 C++ 처럼 좋은 도구가 있음에도 올바르게 이해못하는 사람들이
많은데 과연 C 언어 가지고 객체지향을 프로그래밍하면 어떤 결과가 나올지 눈에 선하군요.

gimmesilver의 이미지

CN wrote:
Agbird wrote:
뭔가 오해하셨군요. 제 주장의 요지는 언어는 단순한 도구가 아니라 사고의 틀을 제공한다는 것입니다.

최초의 Simula는 Algol에 대한 wrapper에 불과했습니다. Simula가 개념적으로 미숙한 것은 사실이지만 완전히 지원하지 못했던 것은 캡슐화에 불과합니다. Simula팀에게 Algol은 도구일까요? 사고의 틀일까요? 그들에게 도구이자 사고의 틀일 수도 있고 둘다 아닐지도 모릅니다.

객체 지향 패러다임은 많은 변화를 겪어 왔고 기존의 생각들이 많이 수정되어 왔습니다. 또한 지금도 계속 변화를 겪어 오고 있습니다.
그 이유는 객체 지향이 하늘에 갑자기 뚝 떨어진 것이 아니고 기존의 언어 패러다임을 통해 조금씩 확장을 해나가는 과정에서 생겨났기 때문일 것입니다.
말씀하신 것처럼 simula 역시 algol의 확장을 통해 시작했습니다. 따라서 simula의 언어 패러다임은 algol의 패러다임에 많은 영향을 받았을 것입니다. C++가 C에게서 그러했듯이...
어쨌든 시작은 미약한 법이고 기존 패러다임의 도움을 받을 수 밖에 없습니다.
그러나 처음에 다소 어설프고 모호하던 객체 지향 패러다임은 algol이나 C가 아닌 simula나 smalltalk, JAVA등과 같은 객체 지향 언어를 통해 보다 구체화 되고 명확해졌을 것이고 따라서 본격적인 객체 지향 패러다임의 모습을 띠게 되었을 것입니다.
만약 계속 기존의 비 객체 지향적인 언어들만을 이용했다라면 객체 지향 패러다임은 현재처럼 발전하지 못했을 것입니다.
전 디자인 패턴과 같은 객체 지향 설계 기법들이 smalltalk가 아닌 C프로그래머를 통해 나올 수 있으리라고는 생각하지 않습니다.
객체 지향적인 사고를 가지기 위해서는 객체 지향 언어를 사용해야 하는 것은 당연하다고 생각합니다.
단순히 객체 지향의 특성을 흉내내는 것과 객체 지향적인 사고를 갖는 것을 구별해서 생각해 주시기 바랍니다.

------------------------
http://agbird.egloos.com

gimmesilver의 이미지

김경태 wrote:
상속 -> 됩니다. pointer to structure 입니다.
method -> 됩니다. pointer to funtion 입니다.
encaptualation(맞나?) -> protect, private 등은 compiler 차원에서 지원되는 것 같습니다.
aggregation -> nested structure 입니다.

pure virtual function-> 됩니다. a->b->c(); 로 합니다.
over loading -> 이건 compiler에서 지원하는 듯 합니다.
name mangling 맞나? 암튼 a() -> a123()
과 같이 실제 컴파일러에서는 다른 이름을 사용
함으로서 같은 이름의 다른 펑션을 구분합니다.
over riding -> pure virtual function과 마찬가지 원리입니다.
소멸자, 생성자-> 당연됩니다. pointer to function입니다.
this pointer -> pointer to function에다 self structure의 pointer를 넘겨줍니다. ^^;

이거 말고 뭘 또 원하시는지?
대표적인 예는 tcp/ip stack이나 VFS source를 보세요.

OO의 개념은 시스템적으로 보면 code segment와 data segment의 <결합>입니다.

비 객체 지향적인 시각에서 봤을 때 클래스는 code과 data의 결합, 다시 말하면 함수와 변수의 결합으로 보일 것입니다.
그러나 객체 지향에서의 클래스는 그런 외향적인 것이 '결코' 아닙니다.
단순히 C의 구조체와 함수 포인터를 이용해서 클래스를 흉내내는 것이 바람직하지 못하다고 주장하는 것은 바로 이런 오해를 할 수 있기 때문입니다.
'클래스 = 함수 + 데이터' 이런식의 개념은 이미 - 객체 지향 패러다임이 제대로 이해되지 못하던 - 80년대에 버려진 개념입니다.
그리고 위에 예시한 것처럼 다형성을 흉내내는 것은 객체 지향이 표방하는 '인터페이스에 의한 설계' 개념에 오히려 해가 될 것 같습니다.

------------------------
http://agbird.egloos.com

김경태의 이미지

비 객체 지향적인 시각에서 봤을 때 클래스는 code과 data의 결합, 다시 말하면 함수와 변수의 결합으로 보일 것입니다.
그러나 객체 지향에서의 클래스는 그런 외향적인 것이 '결코' 아닙니다.

-> 답변해주신 많은 분들이 단지 C, C++ 차원에서만 생각하기 때문에 <다른 메모리에 있다>든가 <data와 code의 결합>이라는 부분을 많이들 오해하고 계시군요.

정확하게 말해서 저의 관점이란 것은 외부적으로 드러나는 고급언어인 C, C++차원이 아닌 모든 외부적 코드의 근원인 기계어나 assembly 차원에서 비롯되었음을 잊지 않으셨으면 합니다.

실제 .exe file을 assembly차원에서 고려했다면 <다른 메모리에 있다>는 부분도, <data와 code의 결합>이란 부분도 오해하지 않을 수 있었을 것입니다.

심지어는 저의 관점을 <외향적인> 관점으로 생각하는 일은 더욱더 없었을 것 입니다.


단순히 C의 구조체와 함수 포인터를 이용해서 클래스를 흉내내는 것이 바람직하지 못하다고 주장하는 것은 바로 이런 오해를 할 수 있기 때문입니다.

-> 위에서 말씀드렸다 시피 저의 관점이란 것은 외향적인 생김새에 대한 C, C++ 류의 고급언어에 기초한 관점은 절대 아닙니다.

실행 Process의 memory map에 대해서 이해했다면 C의 structure가 C++의 class의 흉내내기가 아닌 이유를 이해할 수 있을 것입니다.

기계어 자체로 보면 둘은 <완전히 같은 것>입니다.

님께서 계속 고급언어인 C, C++ 아니 C++ 위주의 관점을 가지고 보시니까 모든게 다르게 보이는 거죠.

흉내내기라고 한다면 C++에서도 name mangling인가를 통해서 다른 function을 마치 같은 function인양 사기를 친다고 말할 수도 있을 겁니다.

특정 고급언어 차원에서 너무 일방적인 생각은 좋지 못한 것 같습니다.

'클래스 = 함수 + 데이터' 이런식의 개념은 이미 - 객체 지향 패러다임이 제대로 이해되지 못하던 - 80년대에 버려진 개념입니다.

-> 제가 말했던 것은 단지 클래스 = 함수 + 데이타란 <외향적>관점이 아닙니다.

모든 언어의 기반인 근원적인 관점 즉, 기계어적인 관점으로 볼때 class나 님께서 흉내내기라고 폄하하신 structure나 data segment와 code segment의 결합을 pointer to function을 통해 구현한 점에서볼때는 동일하다는 것입니다.

기계어적인 관점에서 볼때 둘다 pointer to function으로 구현되어 있음에도 불구하고 이것을 compiler의 조작으로 감춘 C++의 행동은 C의 그것에 비해서는 덜 정직해 보이는 것이 사실입니다.


그리고 위에 예시한 것처럼 다형성을 흉내내는 것은 객체 지향이 표방하는 '인터페이스에 의한 설계' 개념에 오히려 해가 될 것 같습니다.

-> 위에서 기계어적인 관점에서 C, C++의 구현방식은 어떻든 완전히 같다고 말했습니다.

따라서 OO를 제대로 이해했다는 전제하에, 또 언어에 대한 습득이 높은 수준이라는 전제하에서 볼때, C와 C++의 선택은 개인의 취향 및 사용환경 등에 대한 문제이지 이것을 두고 무엇이 옳고 무엇이 그르다고 말하는 것은 어불성설이지요.

게다가 이렇게 하면 좋다는 정도도 아닌 이렇게 하지 않으면 해가 된다는 식의 발언은 조금은 과격하게 들리는 것 같습니다.

익명 사용자의 이미지

김경태 wrote:
비 객체 지향적인 시각에서 봤을 때 클래스는 code과 data의 결합, 다시 말하면 함수와 변수의 결합으로 보일 것입니다.
그러나 객체 지향에서의 클래스는 그런 외향적인 것이 '결코' 아닙니다.

-> 답변해주신 많은 분들이 단지 C, C++ 차원에서만 생각하기 때문에 <다른 메모리에 있다>든가 <data와 code의 결합>이라는 부분을 많이들 오해하고 계시군요.

정확하게 말해서 저의 관점이란 것은 외부적으로 드러나는 고급언어인 C, C++차원이 아닌 모든 외부적 코드의 근원인 기계어나 assembly 차원에서 비롯되었음을 잊지 않으셨으면 합니다.

실제 .exe file을 assembly차원에서 고려했다면 <다른 메모리에 있다>는 부분도, <data와 code의 결합>이란 부분도 오해하지 않을 수 있었을 것입니다.

....

숲을 보지 못하고~ 나무만 보는 오류를 범하고 계시는 군요...

객체지향 개념 자체가~ 상당히 고차원에서 모든것을 바라봅니다.
그런 기계 관점으로 객체지향을 본다는것은 객체지향을 잘못 이해했단 이야기 입니다.

아까 딴분이 이야기 했듯이...
객체지향에서의 객체는 함수 + 구조체가 아닙니다.

객체지향은 구현을 위해~ 함수 + 구조체를 이용하는것이라는
생각을 가진 사람 많이 봤습니다. 그리고 그사람들
거희 대부분 객체지향의 이점을 하나도 활용 못했습니다.
그래서 솔직히 저는 C 가지고 객체지향 한다는 사람 못믿겠습니다.

그런 기계어 관점에서 바라보실려면 C++ 의 모든 코드는
C 로도 구현가능하다 라고 이야기 하는게 좋을꺼 같습니다.
객체지향 이야기는 하지 마시고요~

익명 사용자의 이미지

Anonymous wrote:
김경태 wrote:
비 객체 지향적인 시각에서 봤을 때 클래스는 code과 data의 결합, 다시 말하면 함수와 변수의 결합으로 보일 것입니다.
그러나 객체 지향에서의 클래스는 그런 외향적인 것이 '결코' 아닙니다.

-> 답변해주신 많은 분들이 단지 C, C++ 차원에서만 생각하기 때문에 <다른 메모리에 있다>든가 <data와 code의 결합>이라는 부분을 많이들 오해하고 계시군요.

정확하게 말해서 저의 관점이란 것은 외부적으로 드러나는 고급언어인 C, C++차원이 아닌 모든 외부적 코드의 근원인 기계어나 assembly 차원에서 비롯되었음을 잊지 않으셨으면 합니다.

실제 .exe file을 assembly차원에서 고려했다면 <다른 메모리에 있다>는 부분도, <data와 code의 결합>이란 부분도 오해하지 않을 수 있었을 것입니다.

....

숲을 보지 못하고~ 나무만 보는 오류를 범하고 계시는 군요...

객체지향 개념 자체가~ 상당히 고차원에서 모든것을 바라봅니다.
그런 기계 관점으로 객체지향을 본다는것은 객체지향을 잘못 이해했단 이야기 입니다.

아까 딴분이 이야기 했듯이...
객체지향에서의 객체는 함수 + 구조체가 아닙니다.

객체지향은 구현을 위해~ 함수 + 구조체를 이용하는것이라는
생각을 가진 사람 많이 봤습니다. 그리고 그사람들
거희 대부분 객체지향의 이점을 하나도 활용 못했습니다.
그래서 솔직히 저는 C 가지고 객체지향 한다는 사람 못믿겠습니다.

그런 기계어 관점에서 바라보실려면 C++ 의 모든 코드는
C 로도 구현가능하다 라고 이야기 하는게 좋을꺼 같습니다.
객체지향 이야기는 하지 마시고요~

위에서부터 계속 클래스를 함수+구조체식으로 보면 안된다고
하는데 그건 명백히 틀린겁니다.

제가 언제나 하는 얘기지만, 어떤것을 설명하기 위해 요구되는
관점은 크게 두가지 있는데
첫번째가 syntactic approach
두번째가 semantic approach 입니다.

클래스를 함수+구조체식으로 보는것은 첫번째에 해당합니다.
그리고 말씀하시는것중 high-level한 관점이 바로 두번째에
해당합니다.

설명의 스타일이 이렇게 두가지가 있다는것을 고려해보면
첫번째만 말해놓고 두번째를 살짝 생략하는것은 오류에 해당하지만
그렇다고 해서 첫번째 설명이 틀렸다고 얘기하는것도 오류라는
것이죠.

두가지 설명을 모두 제시해야 객체지향에 대한 "필요충분한 설명"
이 됩니다.

이것은 거시적 생화학적 현상을 원자단위로 설명하는것이
다소 힘들긴 하더라도 틀린것은 아니라는것과 마찬가지
얘기입니다.

gimmesilver의 이미지

Quote:

정확하게 말해서 저의 관점이란 것은 외부적으로 드러나는 고급언어인 C, C++차원이 아닌 모든 외부적 코드의 근원인 기계어나 assembly 차원에서 비롯되었음을 잊지 않으셨으면 합니다.

님이 말씀하신 근원적인 관점에서 바라본다면 클래스나 구조체나 결국은 메모리 처리에 불과합니다. 그렇게 따진다면 이 세상의 모든 컴퓨터 작업은 결국 전기를 껐다 켰다 하는 스위칭 작업에 불과한 것이 되고 맙니다...
기계에적인 관점에서 C와 C++이 같다고 말한다면 세상에 어느 언어가 다르겠습니까? 심지어 배열과 구조체의 차이는 무엇이며 분기문과 함수의 차이는 무엇입니까? 모든 언어 문법의 차이는 무엇이겠습니까? 결국 0아니면 1입니다...
우리는 문학을 시, 소설, 수필 등등으로 구분합니다. 그러나 결국 이것은 한글의 초성, 중성, 종성으로 이루어진 문자 집합에 불과합니다. 그렇다면 결국 시나 소설이나 수필은 모두 같은 것입니까?
한 단계 더나아가 같은 시이지만 한글로 된 시와 영문으로 된 시는 근원이 되는 문자가 다르므로 다른 문학 장르가 되는 것입니까?
만약 어떤 A라는 컴파일러가 클래스 내부에 있는 멤버 변수들을 같은 메모리 블럭에 두지 않고 각 타입 별로 다른 메모리 블럭에 위치하도록 구현하였다면 그 컴파일러에서의 클래스와 일반적인 C++컴파일러의 클래스는 이제 다른 것이 되는 것입니까?
패러다임이라는 것은 그런 근원적인(로우레벨) 관점에서 바라보는 대상이 아닙니다.

Quote:

위에서부터 계속 클래스를 함수+구조체식으로 보면 안된다고
하는데 그건 명백히 틀린겁니다.

제가 언제나 하는 얘기지만, 어떤것을 설명하기 위해 요구되는
관점은 크게 두가지 있는데
첫번째가 syntactic approach
두번째가 semantic approach 입니다.

클래스를 함수+구조체식으로 보는것은 첫번째에 해당합니다.
그리고 말씀하시는것중 high-level한 관점이 바로 두번째에
해당합니다.

syntactic approach는 객체 지향 언어를 설명할 때 사용하는 관점이 될 수는 있습니다. 그러나 객체 지향 패러다임을 설명하는데에는 필요가 없는 개념일뿐더러 오히려 때론 객체 지향적 사고 방식을 방해하는 요소가 될 수도 있습니다.
예를 들어 '클래스'를 함수+구조체식으로 바라본다면 단위 전략 클래스나 인터페이스를 어떻게 이해할 수 있겠습니까?
객체 지향적인 사고에서 클래스는 '책임을 지닌 것'입니다. '객체 = 책임'이라는 패러다임을 가져야 객체 지향적인 사고가 가능합니다.

상속은 구현적인 관점에서 봤을 때 결국 copy&paste에 불과합니다. 부모 클래스의 public/protected 멤버들을 자식 클래스가 고스란히 복사한 것입니다. 그러나 이런 식으로 이해한다면 절대 올바른 객체 지향적인 상속 관계를 구현할 수 없습니다. 90년 대 이전에 객체 지향은 바로 그런 식으로 이해가 되었었기 때문에 상속을 단순한 기능 확장의 목적으로 남용하였었고 이제 이런 것들은 잘못된 설계라는 것이 널리 알려져 있습니다.

'캡슐화'는 구현적인 관점에서 단순히 관련있는 함수와 데이터를 묶어놓은 것처럼 보입니다. 그러나 '캡슐화'는 더 방대하고 추상적인 개념입니다.

'다형성'은 어떻습니까? 어찌어찌 함수 포인터를 조작해서 '다형성'비슷한 기능을 구현했다고 할 때 그것이 다형성이 가진 패러다임을 뜻하는 것은 아닙니다.

근원적인 것을 따져 들어가는 것도 좋지만 보다 사고의 수준을 높이기 위해서는 추상화가 반드시 필요합니다. 그리고 그런 추상화를 도와 주는 것이 그런 패러다임에 걸맞는 언어인 것입니다.

객체 지향 패러다임에 맞지 않는 언어를 이용해서 객체 지향을 이해하려하면 외형적인 형태를 흉내내는 것에 사고의 초점이 맞춰질 수 있기 때문에 객체 지향적 사고에 방해가 되는 것입니다.

------------------------
http://agbird.egloos.com

creativeidler의 이미지

CN wrote:

Objective C에서 nil은 객체의 하나에 불과하고 Objective C의 메소드의 리턴은 디폴트가 객체입니다. 굳이 equals를 bool형으로 반환 값을 규정했다면 에러를 내고 예외를 낼 것이니 문제가 안됩니다. 그리고 디폴트인 객체를 이용했다면 호출자는 nil이 들어온 것을 쉽게 앍아내고 처리해낼 수 있을 것입니다. 더구나 한 발 앞서 equals라는 메시지를 처리할 수 있느냐를 미리 판단하고 적합한 객체에게 전달할 수 있습니다. (일컨데 예외처리를 담당하는 객체도 가능하겠지요.)

잘 이해가 안되는데요. 앞서 하신 말씀과 안 맞는 것 같은데요. 반환값의 문제가 아니라 nil.someMethod는 그 자체로 예외가 발생해야 좋은 코드가 된다는 얘기를 한 것입니다. 근데 앞에선 nil.someMethod가 문제 없이(?) 실행된다고 하셨잖습니까. 사실 nil.someMethod같은 상황은 그 자체가 문제인데 실행되면 안된다..이런 얘깁니다.

Quote:

그리고 몇가지 더 이야기를 꺼낼려고 합니다. Objective C에는 카테고리와 프로토콜이라는 개념이 지원되고 있습니다. 프로토콜이란 개념은 자바와 인터페이스와 유사한 개념인데 Objective C 클래스 전체 혹은 일부에 인터페이스를 강제할 수 있습니다. 이런 행위 패턴은 C++에서는 힘든 방법입니다. 거기에 더 나아가 카테고리라는 개념을 통해서 클래스를 수평적 확장이 가능합니다. 이 수평적 확장은 원본 클래스의 소스코드가 존재하지 않을때도 가능합니다. Simula 형태의 상속을 이용한 C++의 경우 상속을 이용한 수직적 확장만 가능하며 원본의 소스코드가 없을 경우 확장이 힘들어 집니다. 카테고리 기능은 클래스의 메소드를 추가 혹은 수정하여 새로운 클래스 명칭을 붙이는 기능입니다.

구체적인 코드를 보여주시면 좋겠네요. 자바의 인터페이스 개념은 C++에서도 얼마든지 가능합니다. C++도 소스 코드 없이 확장 가능합니다. 카테고리 기능이 클래스의 메소드를 추가 혹은 수정하여 새로운 클래스의 명칭을 붙이는 것이라면 그게 바로 상속 아닌가요? 어떤 차이가 있는지 모르겠습니다.

Quote:

더구나 다형성 면에서는 함수의 전달인자에 의한 함수 테이블 선택 형태인 C++보다는 훨씬 발전된 형태를 가지고 있습니다. Objective C는 클래스의 정보를 담기 위한 메타 클래스가 존재하며 루트 클래스는 보다 세밀한 수준의 메모리 관리, 객체 관리, 타입 관리 등의 정보를 런타임으로 제공해주고 이 루트 클래스는 (Java의 Object와는 달리) 유저가 사용 여부를 선택할 수 있습니다. 메타 클래스와 루트 클래스의 도움으로 Objective의 다형성은 보다 넒은 범위에서 적용이 가능합니다. Objective C의 메시지는 상속관계를 통들어서 관련 객체 모두에게 전달될 수도 있으며 단일 객체에만 전달 될 수도 있고 전달될 객체를 선택할 수도 있습니다. 이 메시지로 인한 호출은 상속관계에만 좌우되지 않고 동일한 메소드 명칭과 인자 명칭을 가진 메소드도 호출이 가능합니다. C++은 스몰토크나 Objective C만큼 메시지를 "메시지"답게 처리할 수 없습니다.

말씀하신 것 모두 다 C++에서 자연스럽게 구현되는 것 같은데요.

show me the code plz.

프로그래머는 코드로 대화해야한다고 생각합니다. 특히나 이런 문제에 관해서는 더욱 그렇지 않을까요? 구체적으로 두 코드를 비교해서 한 쪽이 왜 좋은지를 설명하지 못한다면 납득하기 어렵습니다.

죠커의 이미지

creativeidler wrote:
잘 이해가 안되는데요. 앞서 하신 말씀과 안 맞는 것 같은데요. 반환값의 문제가 아니라 nil.someMethod는 그 자체로 예외가 발생해야 좋은 코드가 된다는 얘기를 한 것입니다. 근데 앞에선 nil.someMethod가 문제 없이(?) 실행된다고 하셨잖습니까. 사실 nil.someMethod같은 상황은 그 자체가 문제인데 실행되면 안된다..이런 얘깁니다.

이해가 안되는 부분이 있어 반대로 질문을 드리겠습니다. [nil someMethod]이 nil을 반환하는게 무엇인 문제인가요?

creativeidler wrote:
구체적인 코드를 보여주시면 좋겠네요. 자바의 인터페이스 개념은 C++에서도 얼마든지 가능합니다. C++도 소스 코드 없이 확장 가능합니다. 카테고리 기능이 클래스의 메소드를 추가 혹은 수정하여 새로운 클래스의 명칭을 붙이는 것이라면 그게 바로 상속 아닌가요? 어떤 차이가 있는지 모르겠습니다.

먼저 앞의 글에서 대답이 될만한 부분에 Bold 표기를 하고 시작하겠습니다.

Quote:
그리고 몇가지 더 이야기를 꺼낼려고 합니다. Objective C에는 카테고리와 프로토콜이라는 개념이 지원되고 있습니다. 프로토콜이란 개념은 자바와 인터페이스와 유사한 개념인데 Objective C 클래스 전체 혹은 일부에 인터페이스를 강제할 수 있습니다. 이런 행위 패턴은 C++에서는 힘든 방법입니다. 거기에 더 나아가 카테고리라는 개념을 통해서 클래스를 수평적 확장이 가능합니다. 이 수평적 확장은 원본 클래스의 소스코드가 존재하지 않을때도 가능합니다. Simula 형태의 상속을 이용한 C++의 경우 상속을 이용한 수직적 확장만 가능하며 원본의 소스코드가 없을 경우 확장이 힘들어 집니다. 카테고리 기능은 클래스의 메소드를 추가 혹은 수정하여 새로운 클래스 명칭을 붙이는 기능입니다.

1. 상속이 부모 자식 관계를 벗어나서 전체 객체 사이에 범용적으로 적용될 수 있습니까?

2. A 클래스를 상속받은 B 클래스만 제공 받았다면 B 클래스의 중복없이 상속으로 B 클래스의 내용을 제거할 수 있습니까?

2. 상속이 부모 객체의 private 메소드를 자유롭게 다룰 수 있습니까?

creativeidler wrote:
말씀하신 것 모두 다 C++에서 자연스럽게 구현되는 것 같은데요.

show me the code plz.

코드를 제시하지 않았던 것은 Objective C의 코드가 creativeidler님에게 실질적으로 도움이 안될 것이라고 믿었고 C++에서 비슷한 코드가 구현이 불가능하거나 현실적으로 힘들어서 상대적인 비교가 되기 힘들어서라고 판단했기 때문입니다. 소스를 보여주지 않고 기능의 나열로 이야기하는 것이 더 현명하다고 생각했습니다. 내 생각엔 안되는 것 같은데 creativeilder님은 된다고 하시니 이전의 글에 체크를 해두고 질문을 드리겠습니다.

Quote:
더구나 다형성 면에서는 함수의 전달인자에 의한 함수 테이블 선택 형태인 C++보다는 훨씬 발전된 형태를 가지고 있습니다. Objective C는 클래스의 정보를 담기 위한 메타 클래스가 존재하며 루트 클래스는 보다 세밀한 수준의 메모리 관리, 객체 관리, 타입 관리 등의 정보를 런타임으로 제공해주고 이 루트 클래스는 (Java의 Object와는 달리) 유저가 사용 여부를 선택할 수 있습니다. 메타 클래스와 루트 클래스의 도움으로 Objective의 다형성은 보다 넒은 범위에서 적용이 가능합니다. Objective C의 메시지는 상속관계를 통들어서 관련 객체 모두에게 전달될 수도 있으며 단일 객체에만 전달 될 수도 있고 전달될 객체를 선택할 수도 있습니다. 이 메시지로 인한 호출은 상속관계에만 좌우되지 않고 동일한 메소드 명칭과 인자 명칭을 가진 메소드도 호출이 가능합니다. C++은 스몰토크나 Objective C만큼 메시지를 "메시지"답게 처리할 수 없습니다.

1. C++ 언어에서 제공해주는 런타임이 얼마나 되나요? 그리고 그것을 신용할 수 있나요? type_info::name() 함수가 int형에 대해서 "int"라는 문자열을 반환해주실 것으로 믿습니까?

2. 위의 모든 것을 이식성을 버리고 creativeilder님이 구현하였다고 가정합시다. 또 모든 객체에 대하여 레퍼런스 카운터만이라도 다형성을 보장할 수 있습니까?

3. 템플릿의 도움을 받지 않고 인터페이스가 공유되지 못하는 서로 다른 두 객체를 받아와서 같은 이름의 메소드를 수행할 수 있겠습니까?

4. 만약 템플릿의 도움을 받는다면 가상 함수에 대해서도 다형성을 보장할 수 있겠습니까? 그리고 동적으로 다른 객체를 템플릿에 받을 수 있겠습니까?

5. A<-B<-C<-D간의 상속관계를 가진 객체가 있다면 암시적으로 D의 객체의 메소드를 실행시키는 것 이외에 명시적으로 A,B,C의 메소드를 실행시킬 방법이 있을까요? 거기에다가 호출하는 측에서 B와 C의 메소드만 호출한다는 식의 정책을 정할 수 있나요?

6. 그것 역시 해내셨다면 이제는 상속관계가 없는 여러 객체들 사이에서 원하는 메시지에 해당하는 메소드를 복수개 실행시킬 방법이 있나요?

익명 사용자의 이미지

숲을 보지 못하고~ 나무만 보는 오류를 범하고 계시는 군요...

객체지향 개념 자체가~ 상당히 고차원에서 모든것을 바라봅니다.
그런 기계 관점으로 객체지향을 본다는것은 객체지향을 잘못 이해했단 이야기 입니다.

아까 딴분이 이야기 했듯이...
객체지향에서의 객체는 함수 + 구조체가 아닙니다.

객체지향은 구현을 위해~ 함수 + 구조체를 이용하는것이라는
생각을 가진 사람 많이 봤습니다. 그리고 그사람들
거희 대부분 객체지향의 이점을 하나도 활용 못했습니다.
그래서 솔직히 저는 C 가지고 객체지향 한다는 사람 못믿겠습니다.

그런 기계어 관점에서 바라보실려면 C++ 의 모든 코드는
C 로도 구현가능하다 라고 이야기 하는게 좋을꺼 같습니다.
객체지향 이야기는 하지 마시고요~

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

처음부터 제가 말했던 것은 data segment와 code segment의 결합을 말했던 것인데 제대로 어의조차 모르시는 분이 객체 = data + 함수가 아니라느니 혹은 객체 = 함수 + 구조체가 아니다라느니라며 하지도 않은 말을 지어내고 계시군요.

객체 = data + 함수라는 것은 OO에 대한 객체 정립이 않된 사람이나 할 수 있는 어처구니 있는 개념의 오역이며 무식의 소치라고 봅니다.

객체 = 함수 + 구조체라는 말은 더욱더 어이없는 OO에 대한 무개념의 발현 이상도 이하도 아닙니다.

그리고 data + 함수라는 말과 함수 + 구조체란 말도 하늘과 땅 차이만큼 많은 어의적 차이가 있구요.

그러나 <data segment와 code segment의 결합>이란 말은 전혀 차원이 틀린 부분입니다. 이건 분명 개념을 말하는 것이 아닌 구현방식에 대한 기계어적인 관점을 말하는 것이며 이는 전혀 틀린 부분이 없는 것입니다.

이 부분에 대해 반박하려거든 되지도 않는 OO기초개념 들이대지 말고 간단히 프로그램 하나 짜서 assembly 차원에서 한번 찬찬히 제 말을 반박해 보시기 바랍니다.

그런데 관점이 완전히 틀린 부분을 엉뚱하게도 OO에 대한 기초적인 개념문제로 자기 멋대로 오역해서, 그것도 전혀 비슷하지도 않은 어휘변형까지 해가면서 비난한다는 것은 자신의 정당성을 증명한다기 보다는 엄밀히 말해서 자기 스스로의 지적, 정신적 미성숙을 말하는 것 이상이 될 수 없겠습니다.

비난을 하던 비판을 하던 다 좋은데 말하지도 않은 부분을 가지고 자기 멋대로 어휘까지 변경시켜가면서 국민학생이면 다 알만한 상식가지고 우쭐거리면서 한수가르쳐준다는 식의 글은 앞으로 웬만하면 올리지 않도록 권유해 마지 않습니다.

gimmesilver의 이미지

제 글을 직접 인용하시진 않았지만 저에게도 해당되는 말씀으로 생각하고 답변 드립니다.

Quote:

처음부터 제가 말했던 것은 data segment와 code segment의 결합을 말했던 것인데 제대로 어의조차 모르시는 분이 객체 = data + 함수가 아니라느니 혹은 객체 = 함수 + 구조체가 아니다라느니라며 하지도 않은 말을 지어내고 계시군요.

객체 = data + 함수라는 것은 OO에 대한 객체 정립이 않된 사람이나 할 수 있는 어처구니 있는 개념의 오역이며 무식의 소치라고 봅니다.

객체 = 함수 + 구조체라는 말은 더욱더 어이없는 OO에 대한 무개념의 발현 이상도 이하도 아닙니다.

그리고 data + 함수라는 말과 함수 + 구조체란 말도 하늘과 땅 차이만큼 많은 어의적 차이가 있구요.

그러나 <data segment와 code segment의 결합>이란 말은 전혀 차원이 틀린 부분입니다. 이건 분명 개념을 말하는 것이 아닌 구현방식에 대한 기계어적인 관점을 말하는 것이며 이는 전혀 틀린 부분이 없는 것입니다.

제가 어셈블리어를 깊게 알지 못해서인지 몰라도 'data segment와 code segment의 결합'이라는 말이 '데이터 + 함수'라는 말과 어의적으로 얼마나 큰 차이가 있는지는 잘 모르겠습니다.
어쨌든 '객체가 data segment와 code segment의 결합이다'라는 말이 틀렸다는 것이 아닙니다. 그렇게 바라보는 관점이 비 객체 지향적이라는 것입니다. 님의 표현대로라면 '구현방식에 대한 기계어적인 관점'인 것이지요...
제가 처음 언급했었던 객체 지향 언어가 아닌 언어로 객체 지향을 흉내내는 것이 바람직하지 못하다는 이야기는 결국 그런 관점이 객체 지향 개념을 이해하는데 도움이 되지 못한다는 뜻입니다.
단지 '아 클래스라는게 이렇게 구현될 수 있겠구나'하는 정도일 뿐이며 이것은 객체 지향 패러다임을 이해하는 것이 아니라 그냥 클래스 구조에 대한 로우 레벨 차원의 이해가 될 뿐입니다.

Quote:

이 부분에 대해 반박하려거든 되지도 않는 OO기초개념 들이대지 말고 간단히 프로그램 하나 짜서 assembly 차원에서 한번 찬찬히 제 말을 반박해 보시기 바랍니다.

저는 어셈블리어를 잘 모르기 때문에 분석을 못하겠군요. 하지만 아마 어셈블리어 수준에서 본다면 님의 말씀이 맞을 겁니다. 객체 - 뿐만이 아니라 프로그램 자체 - 라는 것이 결국 data segment와 code segment 외에 무엇이 있겠습니까? 어차피 - 어떤 언어를 가지고 프로그래밍을 하든지 - 컴파일(혹은 인터프리팅) 후에는 다 똑같은 것일테니까요...
그런데 프로그램을 assembly차원에서 찬찬히 훝어 보는 것이 과연 객체 지향을 이해하는데 도움이 될까요? 그것은 assembly 차원에서 이해하는 것이지 객체 지향 차원에서 이해하는 것이 아닙니다.
왜냐하면 어셈블리어는 객체 지향 패러다임에 적합한 추상화를 제공해 주지 못하기 때문입니다.
모든 것을 객체가 아닌 data segment와 code segment단위로 바라 보고 함수 호출을 레지스터 및 세그먼트 제어로 바라 보는 것은 어셈블리어가 제공하는 패러다임의 시각입니다.
이런 시각에서 봤을 때 객체와 '구조체+함수 포인터'는 차이가 없어 보입니다. 그러나 바로 그 점이 잘못됐다는 것입니다. 올바른 객체 지향 프로그래밍을 위해서는 객체를 다르게 봐야 합니다. 그런데 C와 같은 객체 지향 패러다임이 없는 언어로 객체를 구현하게 되면 바로 그런 점을 혼동할 소지가 높다는 것입니다.

왜 수많은 패러다임을 가진 언어가 세상에 만들어지겠습니까? 그것은 어떤 패러다임을 가지고 프로그래밍을 하기 위해서는 그 패러다임에 적합한 언어를 가지고 프로그래밍 하는 것이 가장 바람직하기 때문입니다.
모든 사람들이 고도의 지능을 가지고 있어서 어셈블리어를 가지고도 아니면 전기 스위치의 조합만으로도 충분히 추상화된 사고가 가능하다면 그럴 필요가 없을 것입니다.
그러나 사람의 사고 수준은 한계가 있기 때문에 추상화와 계층화가 필요한 것입니다. 그리고 그런 추상화나 계층화를 도와 주는 것이 언어이고 플랫폼이 아니겠습니까?

이전 글 하나 인용하겠습니다.

Quote:

OO를 제대로 이해했다는 전제하에, 또 언어에 대한 습득이 높은 수준이라는 전제하에서 볼때, C와 C++의 선택은 개인의 취향 및 사용환경 등에 대한 문제이지 이것을 두고 무엇이 옳고 무엇이 그르다고 말하는 것은 어불성설이지요.

OO를 제대로 이해했다면 어떤 언어를 선택하든 상관없다는 말은 일면 타당해 보이지만 제 생각에는 최대한 패러다임에 적합한 언어를 선택하거나 혹은 자신이 가장 잘하는 언어에 적합한 패러다임을 가지고 프로그래밍 하는 것이 옳다고 봅니다.
C를 이용한다면 굳이 객체 지향 프로그래밍을 할 필요가 없습니다. C에 적합한 패러다임으로 '문제 해결 방법을 구현'하면 됩니다.
종이를 자르기 위해서 가위를 이용할 때는 가위질을 하면 되고 칼을 사용할 때는 칼질을 하면 됩니다. 굳이 가위의 한쪽 날을 가지고 칼질을 흉내내거나 칼 두개를 연결해서 가위질을 흉내낼 필요는 없습니다.

------------------------
http://agbird.egloos.com

익명 사용자의 이미지

Agbird wrote:

syntactic approach는 객체 지향 언어를 설명할 때 사용하는 관점이 될 수는 있습니다. 그러나 객체 지향 패러다임을 설명하는데에는 필요가 없는 개념일뿐더러 오히려 때론 객체 지향적 사고 방식을 방해하는 요소가 될 수도 있습니다.
예를 들어 '클래스'를 함수+구조체식으로 바라본다면 단위 전략 클래스나 인터페이스를 어떻게 이해할 수 있겠습니까?
객체 지향적인 사고에서 클래스는 '책임을 지닌 것'입니다. '객체 = 책임'이라는 패러다임을 가져야 객체 지향적인 사고가 가능합니다.

상속은 구현적인 관점에서 봤을 때 결국 copy&paste에 불과합니다. 부모 클래스의 public/protected 멤버들을 자식 클래스가 고스란히 복사한 것입니다. 그러나 이런 식으로 이해한다면 절대 올바른 객체 지향적인 상속 관계를 구현할 수 없습니다. 90년 대 이전에 객체 지향은 바로 그런 식으로 이해가 되었었기 때문에 상속을 단순한 기능 확장의 목적으로 남용하였었고 이제 이런 것들은 잘못된 설계라는 것이 널리 알려져 있습니다.

'캡슐화'는 구현적인 관점에서 단순히 관련있는 함수와 데이터를 묶어놓은 것처럼 보입니다. 그러나 '캡슐화'는 더 방대하고 추상적인 개념입니다.

'다형성'은 어떻습니까? 어찌어찌 함수 포인터를 조작해서 '다형성'비슷한 기능을 구현했다고 할 때 그것이 다형성이 가진 패러다임을 뜻하는 것은 아닙니다.

근원적인 것을 따져 들어가는 것도 좋지만 보다 사고의 수준을 높이기 위해서는 추상화가 반드시 필요합니다. 그리고 그런 추상화를 도와 주는 것이 그런 패러다임에 걸맞는 언어인 것입니다.

객체 지향 패러다임에 맞지 않는 언어를 이용해서 객체 지향을 이해하려하면 외형적인 형태를 흉내내는 것에 사고의 초점이 맞춰질 수 있기 때문에 객체 지향적 사고에 방해가 되는 것입니다.

저는 두가지 방식의 설명방식이 모두 필요하다고 했지, syntactic한 설명만으로 충분하다고 한적이 없습니다. 마치 제가 그렇게 글을 쓴것처럼 몰아세우시네요.

"저는 객체=함수+구조체 로 설명하는것이 틀렸다"라는 것 자체를 반박하고 있는것입니다. (물론 이것은 data segment+code segment와는 또 다른 얘기입니다.) 그것은 틀린설명이 아니라 불충분한 설명일뿐입니다. 불충분한 설명을 틀린 설명인것처럼 뜻을 왜곡하지 마시기 바랍니다.

익명 사용자의 이미지

윗글은 제가 쓴것이고요... 하나 더 추가하자면..
어떤 개념이든 구현관점에서 바라보는것은 그것이 완전히 추상화된 형태로
주어졌을때 놓치기 쉬운것들을 올바로 집어낼 수 있도록 해줍니다.

추상성과 구체성을 동시에 가져가는것이 어느 하나만 가져가는것보다
어떤 개념에 대한 훨씬 깊은 이해를 할 수 있게 해준다는것입니다.

때문에 여기 계신 상당수의 분들이 마치 객체지향에 대해선 추상성만을 내 세울 수 있다고 주장하시는데 그건 소프트웨어 공학의 역사속에서 객체지향이 태어났던 주요 동기에 의해 정당화 될수 있는 말일수는 있어도 실제로 객체지향 개념과 언어를 익히고, 사용하는 입장에서는 충분하지 않은 논변입니다.

익명 사용자의 이미지

Anonymous wrote:
처음부터 제가 말했던 것은 data segment와 code segment의 결합을 말했던 것인데 제대로 어의조차 모르시는 분이 객체 = data + 함수가 아니라느니 혹은 객체 = 함수 + 구조체가 아니다라느니라며 하지도 않은 말을 지어내고 계시군요.

객체 = data + 함수라는 것은 OO에 대한 객체 정립이 않된 사람이나 할 수 있는 어처구니 있는 개념의 오역이며 무식의 소치라고 봅니다.

객체 = 함수 + 구조체라는 말은 더욱더 어이없는 OO에 대한 무개념의 발현 이상도 이하도 아닙니다.

그리고 data + 함수라는 말과 함수 + 구조체란 말도 하늘과 땅 차이만큼 많은 어의적 차이가 있구요.

그러나 <data segment와 code segment의 결합>이란 말은 전혀 차원이 틀린 부분입니다. 이건 분명 개념을 말하는 것이 아닌 구현방식에 대한 기계어적인 관점을 말하는 것이며 이는 전혀 틀린 부분이 없는 것입니다.

이 부분에 대해 반박하려거든 되지도 않는 OO기초개념 들이대지 말고 간단히 프로그램 하나 짜서 assembly 차원에서 한번 찬찬히 제 말을 반박해 보시기 바랍니다.

그런데 관점이 완전히 틀린 부분을 엉뚱하게도 OO에 대한 기초적인 개념문제로 자기 멋대로 오역해서, 그것도 전혀 비슷하지도 않은 어휘변형까지 해가면서 비난한다는 것은 자신의 정당성을 증명한다기 보다는 엄밀히 말해서 자기 스스로의 지적, 정신적 미성숙을 말하는 것 이상이 될 수 없겠습니다.

비난을 하던 비판을 하던 다 좋은데 말하지도 않은 부분을 가지고 자기 멋대로 어휘까지 변경시켜가면서 국민학생이면 다 알만한 상식가지고 우쭐거리면서 한수가르쳐준다는 식의 글은 앞으로 웬만하면 올리지 않도록 권유해 마지 않습니다.

그렇게 이해 하셨다면 죄송합니다...

서로 같은 말만 계속 하기 때문에
저로선 마지막 정리 하겠습니다.
전 지금 C 언어 가지고 OOP 한다는 글을

I am a boy
아이 엠 어 보이

똑같이 발음되기 때문에 같은 영어다 라고 말하는것과 같이 보입니다.
어짜피 대부분의 한국 사람에게는 두개는 똑같이 발음되기 때문에
한국사람에게만 사용한다고 가정하면 둘다 영어가 되는것입니까?
두개가 똑같이 발음 된다고 해서 두개가 같은건 아닙니다.

둘다 똑같은 어셈이 된다고 해서 두개가 같은게 되는건 아닙니다.

여기까지 제생각입니다.

익명 사용자의 이미지

음. 재밌는 주제로 역시다 다시 토론하고들 계시네요...
(저 역시 프로그램을 복잡하게 작성하는것을 좋아하는 편이지만...)

충분한 동작을 하는,
- 간단하게 이해할 수 있는 프로그램.
- 여러가지 배경지식을 갖춰야만 충분히 이해할 수 있는 프로그램.
과연 어느게 좋은 프로그램인지...

OOP는 OOPL만으로 해야하는건지...
아니면 OOP는 OOP일 뿐, OOPL으로만 해야한다는건 억지인지...

여러분들의 그리고 일반적인 혹시 OO의 관점에서..
fopen, fwrite, fread 등과 같은 함수들은 어떻게 보여지나요 ???
단지 허접한 OO의 모습을 따라하려고한, 이러한 접근은 하지 말았어야하는..
그런 쓰레기같은 부산물의 하나인가요 ???

C로 OO를 하면 안된다고 하시는 분들께 묻고싶습니다.

사견입니다만...
I am a boy.
Im a boy.
/aiem_cb_ci/ <= c 거꾸로한 기호를 표현할 수 없어서... _c로 했습니다만.
아이엠어보이.
어디까지가 영어이고, 어디까지가 영어가 아닌지요...
그렇담
'신도림역이 여기 인가요?'라고
한국인이 얘기한것과,
어설프게 외국인이 예기한것중..
후자는 한글이 아닌가요 ???
^^;;

익명 사용자의 이미지

Anonymous wrote:

객체 = data + 함수라는 것은 OO에 대한 객체 정립이 않된 사람이나 할 수 있는 어처구니 있는 개념의 오역이며 무식의 소치라고 봅니다.

대부분의 생각에 동의하는데 이 부분은 아닌것 같군요.
code segment+data segment 식의 설명이 정당하다는것엔
저도 전적으로 동감합니다만, 이렇게 볼 수 있는것과 마찬가지로
좀 더 level을 높여 data+함수 이렇게 보는것도 정당합니다.

여기 계신분들은 levels of explanation 을 고려하는데
별로 익숙하지 않은것 같습니다.

저는 어떤 차원의 설명이라도 그것이 동일한 실재를 반영하는것이
라면 각자가 유의미한 설명이 될 수 있다고 생각하는 사람이고,
이것은 이미 이 분야뿐만 아니라 과학일반에서 받아들여지고
있는 핵심 컨셉이라고 봅니다.

code segment+data segment 이렇게 보는것도
data+함수로 보는것도,
또 자율성과 책임이 부여된 ADT의 한 단위로 보는것도
모두 다 가능하며 또 정당한 설명이라고 생각합니다.

creativeidler의 이미지

Quote:
이해가 안되는 부분이 있어 반대로 질문을 드리겠습니다. [nil someMethod]이 nil을 반환하는게 무엇인 문제인가요?

nil을 반환해서 if (nil)이 예외를 발생시킨다면 OK입니다. 하지만 만약 if (nil)이 if (false)로 간주가 된다면 그건 버그를 은폐하는 코드가 되기 때문에 나쁘다는 것이죠. 지금까지 CN님이 설명하신 것만 봐서는 후자인 것 같더군요. 예외 상황에서는 예외 처리로 제어가 넘어가는 것이 좋습니다.

Quote:
1. 상속이 부모 자식 관계를 벗어나서 전체 객체 사이에 범용적으로 적용될 수 있습니까?

2. A 클래스를 상속받은 B 클래스만 제공 받았다면 B 클래스의 중복없이 상속으로 B 클래스의 내용을 제거할 수 있습니까?

3. 상속이 부모 객체의 private 메소드를 자유롭게 다룰 수 있습니까?


오, 그거였군요. 그거라면 1, 2, 3번 모두 C++에서는 안되는 기능입니다. 그런데 말입니다. 1,2,3번 모두 OOP에서는 필요 없는, 아니 오히려 금지해야할 기능인 것으로 보입니다. 1번은 클래스 설계자의 의도를 클래스 이용자가 빗나가게 해버릴 수 있다는 문제점이 있고 2번은 나쁜 냄새 목록에 의거하면 Refused Bequest로 리팩토링 대상입니다. 3번, private 메소드는 상속시키길 원지 않기 때문에 private로 한 것인데 이걸 자유롭게 다루고 싶어한다면 그건 클래스 설계가 잘못된 것이죠. 나아가 implementation을 상속하는 것이 OOP에서 권장되는 바가 아니라는 점까지 생각한다면 문법적으로 금지하는 것이 마땅해 보입니다.

Quote:
1. C++ 언어에서 제공해주는 런타임이 얼마나 되나요? 그리고 그것을 신용할 수 있나요? type_info::name() 함수가 int형에 대해서 "int"라는 문자열을 반환해주실 것으로 믿습니까?

2. 위의 모든 것을 이식성을 버리고 creativeilder님이 구현하였다고 가정합시다. 또 모든 객체에 대하여 레퍼런스 카운터만이라도 다형성을 보장할 수 있습니까?

3. 템플릿의 도움을 받지 않고 인터페이스가 공유되지 못하는 서로 다른 두 객체를 받아와서 같은 이름의 메소드를 수행할 수 있겠습니까?

4. 만약 템플릿의 도움을 받는다면 가상 함수에 대해서도 다형성을 보장할 수 있겠습니까? 그리고 동적으로 다른 객체를 템플릿에 받을 수 있겠습니까?

5. A<-B<-C<-D간의 상속관계를 가진 객체가 있다면 암시적으로 D의 객체의 메소드를 실행시키는 것 이외에 명시적으로 A,B,C의 메소드를 실행시킬 방법이 있을까요? 거기에다가 호출하는 측에서 B와 C의 메소드만 호출한다는 식의 정책을 정할 수 있나요?

6. 그것 역시 해내셨다면 이제는 상속관계가 없는 여러 객체들 사이에서 원하는 메시지에 해당하는 메소드를 복수개 실행시킬 방법이 있나요?

용어가 좀.. 런타임은 RTTI를 의미하는 것인가요? 1번은 의도하신 바가 무엇인지 잘 모르겠습니다. 2번도 잘 모르겠네요. 3번은 RTTI로 가능한 것 아닌가요? 4번도 질문의 의도가 뭔지 모르겠네요. 가상 함수는 다형성을 보장하기 위해 존재하는 것 아니던가요? void*라면 템플릿 아니더라도 다양한 객체를 저장할 수 있죠.
5번은 그 객체가 D 타입이라는 가정을 한 것인가요? D타입의 객체를 실행시키면서 부모 객체의 메소드를 실행시키고 싶어하는 경우? 이런 요구사항이 생기는 것 자체가 비 OOP적인 것으로 보입니다만.. 6번도 RTTI로 어느 정도 가능하죠.

CN님 말씀을 듣고 보니 Objective C가 C++보다 기능이 더 많다는 건 알겠습니다. 그런데 더 객체지향적이란 건 동의할 수 없군요. 오히려 객체지향에서 피해야할 것들을 너무도 많이 지원하고 있다는 생각이 드는데요. 사실 OOP에서 문법적으로 어떤 기능들을 더 많이 지원하느냐는 그리 중요하지 않습니다. OOP의 핵심 문법만 잘 지원하면 오히려 간결한 문법일수록 좋죠. Java는 다중 상속도 안되고 operator overloading도 안되는데 왜 C++보다 더 객체지향적인 언어로 평가받을까요? 따지고보면 C++이 훨씬 객체지향적인 문법 지원이 많은데 말입니다. 그것은 아마도 Java가 좀더 객체지향적으로 좋은 코드를 만들도록 유도하기 때문일 것입니다. 지금까지 CN님에게 얻은 정보만으로는 Objective C는 C++보다도 더 해로운 요소가 많은 것 같아 보입니다.

그리고, 제가 Objective C 코드를 읽을 수 없을 것 같아서 코드를 제시하지 않으신 거라면 염려 마시고 제시해주세요. 어차피 같은 패러다임의 언어는 다 비슷비슷한 것 아니겠습니까. 충분히 두 코드를 비교해서 어느 것이 더 좋은지 설명할 수 있고 저도 이해할 수 있을 것입니다. 모르면 제가 잠깐 ㅤㅎㅜㅌ어보고 쳐박아두었던 Objective C 책을 뒤져서라도 이해하려고 노력할 것이니 코드로 제시해주세요. 어차피 CN님의 주장이 Objective C에서 같은 내용으로 C++보다 더 객체지향적으로 구현할 수 있다는 것이니 가장 쉽고 편리한 입증 방법은 코드 비교 아니겠습니까.

김경태의 이미지

약간의 오해와 약간의 감정으로 조금은 겪하게 말했던 바가 있었던 것 같습니다.

마지막으로 제 생각을 정리해서, 가급적 더이상의 오해가 없도록 예를 들어서 정리해보도록 하겠습니다.

DB를 예를 들어 설명해 보겠습니다.

DB를 모르는 사람은 informix나 oracle이나 그냥 DB일 뿐입니다. 전혀 달라보이지 않습니다.

이 사람에게 있어서 informix나 orcle은 같은 DB이고 ansi SQL을 공유하므로 다르지 않은 것입니다.

그러다가 실제 프로젝트에서 informix와 oracle을 실제로 다루는 경험이 있어서 자세한 부분을 알게되면서 같은 DB이지만 informix와 oracle은 정말 많이 다르다는 것을 이해하게 되었습니다.

이 사람에게 있어서는 informix나 oracle은 쓰는 문법도 다르고 환경도 다르니까 다르다고 말할 것입니다.

그러다가 이 사람이 좀 더 깊은 튜닝을 위해서 hint등을 사용하게 되어 index의 원리를 이해하기 위해 자료구조와 파일구조를 공부하고 index의 근본원리인 B+ tree 외 bit map index를 구현차원에서 이해하며 hash를 source 차원에서 이해하게 되었습니다.

이 사람은 informix나 oracle은 비록 syntex, 환경은 다르지만 본질은 하나도 다르지 않으므로 당연히 두 DB는 같다라고 결론지어 말할 것입니다.

Web을 가지고 설명하겠습니다.

처음 web browser를 사용하는 사람에게 있어서는 home page는 asp를 사용하여 window에서 구현했든, php를 이용해서 linux에서 구현했든 모두 같아보일 것입니다.

이 사람이 home page를 구축하려고 좀더 공부해 보니 php, asp, jsp등이 모두 다르고 구현환경도 systex도 모두 다르다는 것을 알았고 이 사람은 web이란 것은 구축환경이나 구현방법에 따라 모두 다르다고 말할 것입니다.

그런데 이사람이 좀더 깊은 이치를 탐구하여 http protocol, tcp/ip protocol, routing의 원리와 IRQ의 원리까지 이해해버렸을 때 이 사람은 드디어 그 모든 것이 H/W적인 작동원리를 통한 packet이라는 놈의 장난임을 깨닫고 web은 결국은 다 같다고 말했습니다.

사실, 첫번째도 두번째도 세번째도 자기 수준에서는 다 맞는 말입니다.

하지만 세번째야말로 가장 깊은 이해이며 가장 정확한 이해인 것입니다.

주의할 것은 말은 <같다>로 비슷하지만 첫번째와 세번째의 이해도는 그야말로 하늘과 땅차이라는 사실입니다.

첫째 단계의 같다는 구체적인 차이를 모르기 때문에 생긴 일종의 오해일 뿐이지만 세번째의 같다라는 것은 <두번째의 구체적인 다름을 포함하고도 본질적인 차원에서는 같다>는 것을 말하는 것으로 두번째의 논지까지를 충분히 이해한 고차원적인 이해입니다.

그런데 두번째의 단계에 있는 사람이 세번째의 단계에서 <같다>라는 언명을 단지 말이 비슷하다는 이유로 첫번째 단계에서의 <같다>라는 뜻으로 오인하고 이것에 대해서 나무라고 있다면 그것은 참으로 문제가 아닐 수 없습니다.

제가 처음 < 시스템적인 관점으로 볼때 객체는 데이타 세그먼트와 코드 세그먼트의 결합>이라고 정의한 것은 객체의 개념을 몰라서 한 소리가 아니고 객체의 개념을 시스템적으로 재해석한 결과를 언명한 것입니다.

그런데 이것을 마치 제가 객체의 개념정리조차 제대로 못한 사람인 것 마냥 매도를 하시고 C, C++의 언어적 특성을 논한다는 것은 애초 저의 언명 자체를 깊이 이해하지 못했다는 말밖에는 될 수 없는 것입니다.

그리고 OOP는 개념이고 OOPL은 language이며 객체는 실체입니다.

따라서 개념인 OOP를 구현하기 위해 즉 객체를 작성하기 위해 OOP를 더 잘 지원하는 OOPL을 사용하여 객체를 구현하는 것이 편할지는 몰라도 only OOPL만이 객체를 구현할 수 있다고 주장하는 것은 어폐가 있는 것입니다.

원론적으로 OOP는 개념이므로 능력만 된다면 assembly로도 객체구현은 가능하고 C로도 객체구현은 가능한 것입니다.

이것은 어디까지나 프로그래머의 능력이나 이해도, 혹은 환경, 시스템의 요구조건 및 선택의 문제일 뿐이지 절대적인 기준으로 강요될 수 있는 것인 아닌 것입니다.

C와 assembly를 생각할때 C로 구현할 수 있는 것을 굳이 assembly로 구현할 필요는 없겠지만 그렇다고해서 C로 구현할 수 있는 function을 assembly로 구현했다고 해서 단지 assembly가 function을 구현하기 불편하다는 이유로 그것을 나쁘다거나 황당한 짓으로 매도할 수는 없는 것입니다.

assembly로 function을 구현하는 것은 어렵기는 하지만 충분히 가능할 뿐더러 오히려 programmer가 원하는 가장 powerfule하고 유연하며 가장 speedy한 코드를 구사할 수 있다는 점에서는 오히려 C로 구현한 function의 구현형태보다도 훨씬 더 나은 점이 있을 수 있는 것입니다.

그리고 저의 경험에 의하면 똑같은 C Programming에 있어서도 assembly와 시스템에 대해서 충분한 이해가 있는 사람과 단순히 C만 아는 사람과의 테크닉의 차이라는 것은 하늘과 땅차이일 때가 많았다는 점도 말씀드리고 싶습니다.

이런 가정은 C 혹은 C++을 사용한 객체구현에도 역시 비슷하게 적용될 수 있다고 생각하고 있습니다.

오해가 오해를 낳다보니 제 나름대로 제 생각을 정리하고 오해의 소지를 최대한 없애려 노력하였으나 이 또한 헛된 말이 더 많은 말을 만들어 낼까 저어되는 바입니다.

모쪼록 오늘 하루도 행복한 시간 되시기 바랍니다.

creativeidler의 이미지

흠. 중간에 조금 이상하게 흘러간 감이 있는데 최초에 C++을 쓸 수 있는 상황에서 굳이 C로 객체지향을 할 필요가 없다는 주장에 대해 C에서 객체지향을 하는 게 뭐가 나뻐..하는 식으로 반론이 제기되면서 오해가 오해를 낳는 것 같습니다.

단순히 C만 써야하는 상황과 C/C++을 모두 쓸 수 있는 상황으로 나눠서 생각해보는 것이 어떨까요? 다음처럼 의견을 분류해볼 수 있을 것 같습니다.

1. C만 써야하는 상황
1-1. C에서도 OOP가 낫다.
1-1. C에서는 OOP보다 SP가 낫다.

2. C/C++을 모두 쓸 수 있는 상황
2-1. OOP를 하고 싶다면 C++을 쓰는 것이 좋다.
2-2. OOP를 하고 싶더라도 굳이 C++을 쓸 필요는 없다.

제 경우는 1-1, 2-1입니다.

gimmesilver의 이미지

guest of htna wrote:

여러분들의 그리고 일반적인 혹시 OO의 관점에서..
fopen, fwrite, fread 등과 같은 함수들은 어떻게 보여지나요 ???
단지 허접한 OO의 모습을 따라하려고한, 이러한 접근은 하지 말았어야하는..
그런 쓰레기같은 부산물의 하나인가요 ???

질문의 의도를 잘 모르겠습니다. fopen(), fwrite(), fread()가 무슨 문제가 있나요?
그런 함수들은 객체 지향이든 다른 어떤 패러다임이든 그냥 함수일 뿐입니다...
패러다임은 문법이나 형태가 아닙니다. 전체 프로그래밍을 위한 사고 방식입니다. 단순히 어떤 함수나 클래스의 외형만을 가지고 이것이 객체 지향적이냐 아니냐를 따질 수는 없습니다.

Quote:

C로 OO를 하면 안된다고 하시는 분들께 묻고싶습니다.

사견입니다만...
I am a boy.
Im a boy.
/aiem_cb_ci/ <= c 거꾸로한 기호를 표현할 수 없어서... _c로 했습니다만.
아이엠어보이.
어디까지가 영어이고, 어디까지가 영어가 아닌지요...

위와 비슷한 이야기입니다. 이것은 패러다임과 상관없는 질문입니다. 이것은 마치

class Test
    {
    public:
        void func() {}
    private:
        int x;
    }

위의 코드가 객체 지향적이냐 그렇지 않으냐? 라고 질문하는 것과 유사합니다. 위의 것은 그냥 클래스를 하나 정의한 것 이상 아무 의미가 없습니다. 클래스를 하나 정의했다고 객체 지향 프로그래밍이 되는 것은 아니기 때문입니다.

흔히 'C++를 이용한 C프로그래밍'이라는 농담섞인 표현이 있습니다. C++문법을 이용하지만 전혀 객체 지향적이지 못한 프로그래밍을 하는 것을 말합니다.

클래스를 사용했다고 해서, 상속이나 다형성을 이용했다고 해서 그것이 곧 객체 지향적으로 프로그래밍을 한 것을 의미하는 것이 아닙니다. 객체 지향적으로 방식으로 디자인을 해야 객체 지향 프로그래밍입니다.

그런데 그런 사고를 얻기 위해서는 패러다임에 맞는 적절한 추상화가 필요한 것이고 그런 추상화를 객체 지향 언어는 제공해 준다는 것입니다. 물론 그렇다 하더라도 객체 지향 패러다임이 머리속에 저절로 생기는 것은 아닙니다. 때문에 우리는 디자인 패턴 같은 것들을 공부하고 노력하는 것이 아니겠습니까?
즉, 객체 지향 언어를 가지고도 객체 지향적인 프로그래밍을 하기위해서는 부단한 노력이 필요합니다.
그런데 비 객체 지향 언어를 이용한다면 객체 지향적인 추상화 자체를 구현해야 한다는 추가적인 부담이 생기기 때문에 어려움이 훨씬 커집니다. 그리고 그런 점 때문에 '비 객체 지향 언어를 사용한 객체 지향 프로그래밍을 하면 나쁘다'라고 주장하는 것입니다.

김경태 wrote:

첫째 단계의 같다는 구체적인 차이를 모르기 때문에 생긴 일종의 오해일 뿐이지만 세번째의 같다라는 것은 <두번째의 구체적인 다름을 포함하고도 본질적인 차원에서는 같다>는 것을 말하는 것으로 말은 틀리지만 두번째의 논지를 충분히 이해한 고차원적인 이해입니다.

그런데 두번째의 단계에 있는 사람이 세번째의 단계에서 <같다>라는 언명을 단지 말이 비슷하다는 이유로 첫번째 단계에서의 <같다>라는 뜻으로 오인하고 이것에 대해서 나무라고 있다면 그것은 참으로 문제가 아닐 수 없습니다.

제가 처음 < 시스템적인 관점으로 볼때 객체는 데이타 세그먼트와 코드 세그먼트의 결합>이라고 정의한 것은 객체의 개념을 몰라서 한 소리가 아니고 객체의 개념을 시스템적으로 재해석한 결과를 언명한 것입니다.

그런데 이것을 마치 제가 객체의 개념정리조차 제대로 못한 사람인 것 마냥 매도를 하시고 C, C++의 언어적 특성을 논한다는 것은 애초 저의 언명 자체를 깊이 이해하지 못했다는 말밖에는 될 수 없는 것입니다.

말씀하신 뜻은 잘 알고 있습니다. 그러고 제가 계속 말씀드리고 있는 것은 객체 지향 언어의 매카니즘을 이해하는 방법이 아니고 객체 지향 프로그래밍을 하는 방법입니다. 말씀하신 것처럼 근원적인 관점에서 객체를 이해하는 것은 의미가 있습니다.
예를 들어

class Test2
    {
    public:
        Test2() : x(0) {}
        void AddInt(int a) { x += a; }
        int GetX() const { return x; }
    private:
        int x;
    }

Test2 t;
t.AddInt(3);

위와 같은 코드가 있다 할 때 Test2::AddInt()함수는

void AddInt(Test2* this, int a)
    {
    this->x += a;
    }

결국 이것과 동일하다는 것은 그 언어의 매카니즘을 이해하는데 도움이 됩니다. 그리고 그런 언어의 매카니즘을 이해하다 보면 결국 C나 C++이나 근원이 같으며 따라서 C를 이용하더라도 C++과 유사한 특성을 구현할 수 있다는 사실 또한 알게 됩니다.
하지만 저는 언어의 매카니즘을 이해하는 것이 객체 지향 패러다임을 이해하는 것과는 다르며 더 나아가 객체 지향적인 프로그래밍을 하는 것 또한 다르다는 점을 주장하고 있는 것입니다.
'결국 근원이 같으면 뭐로 해도 상관없지 않으냐?'라는 생각을 할 수 있지만 저는 그것이 바로 함정이라고 생각합니다.
근원을 이해했다고 해서 모든 것은 근원적 시각에서 바라본다면 그것은 결국 근원적인 사고 방식에서 사고하는 것입니다.
어셈블리어를 이용해서 객체 지향 프로그래밍을 그대로 흉내냈다고 해서 그것이 무슨 의미가 있습니까? 그렇게 흉내낸 소스에서 정말로 객체 지향적인 재사용성이나 확장성을 추구할 수 있을까요? 객체 지향에서 추구하는 동적 가변성을 얻을 수 있을까요?
그것은 지적 유희 내지는 인간 한계 도전일 뿐입니다. 객체 지향 패러다임도 아니고 생산성과 재사용성이라는 객체 지향 목적에도 위배됩니다.

------------------------
http://agbird.egloos.com

김경태의 이미지

질문의 의도를 잘 모르겠습니다. fopen(), fwrite(), fread()가 무슨 문제가 있나요?
그런 함수들은 객체 지향이든 다른 어떤 패러다임이든 그냥 함수일 뿐입니다...

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

대단히 죄송하지만 이글을 읽는 순간 님의 인식의 한계가 눈에 금방 보이는군요.

님은 그저 user interface적인 관점에서 즉, 단지 fopen을 불러다 쓰는 입장에서 fopen은 C함수인데 갑자기 무슨 객체지향 어쩌고 저쩌고를 따지느냐라는 말씀을 하신 것으로 보입니다.

그러나...

fopen(), fread(), fwrite는 VFS에서 돌아가는 함수이며 이것은 device와 독립적인 system call입니다.

또한 이 device라는 놈들은 실시간적으로 binding 되어야 하는 글자 그대로 동적 binding이 필요한 그런 구현이 되어야 한다는 것이지요.(insmod, rmmod)

따라서 이것은 user interface적인 관점에서 보면 그냥 C함수이지만 구현입장에서 생각해보면 OO에서 말하는 pure virtual function이며 다시말해 Componant를 구현하기 위한 Interface역할을 의미합니다.

그런데 이것을 kernel에서는 C로 구현하고 있다는 겁니다.

결국 위의 VFS system call은 구현방법으로 보면 C로 OO의 pure virtual function을 성공적으로 구현한 것인데 이것은 C++로만 객체를 구현해야만 좋다는 논지에서 보면 이러한 LINUX의 kernel code는 그야말로 어설픈 객체 흉내내기에 불과한 쓰레기 코드가 되는 것이 아니냐고 되묻고 있는 겁니다.

제가 파악한 바, 님의 한계는 진실로 C로 구현한 객체란 어떤 것인지 실제적인 예를 아직 한번도 제대로 검토한 적도 없으면서 일반적인 C사용에 대한 기초적인 상식과 C++의 문법이나 객체에 대한 몇가지 이론만 가지고 무조건 객체는 C++로만 구현해야 하고 C로 구현하면 제대로된 객체는 구현 불가능하다라고 말하고 있는 것입니다.

지피지기면 백전 백승이라는 말도 있는데 님께서는 계속 원론적인 부분만 말씀하시지 마시고 가령 위에 예로 들었던 C로 구현된 객체의 전형적인 예제인 VFS kernel source 정도만이라도 직접 분석해 보시고 나서 님의 주의 주장을 펴시는게 훨씬 더 현명해 보이는 것 같습니다.

상대방 주의 주장의 근거가 되는 kernel source나 그 체계가 뭔지 전혀 모르시는 상황에서 무조건 <객체는 C++로만 구현해야 제대로 된 객체다>라고 반복하신다면 그건 결국 일방적인 자기 주장일 뿐이므로 그 어떤 상대도 설득할 수 없지 않을런지요?

wish의 이미지

첫줄에 인신공격을 하신 것 치고는 주장이 그다지 설득력 있지 않습니다.

fopen 등등의 함수는 user-level 의 관점에서는 하나의 C 함수일 뿐입니다.

fopen 은 VFS 에서 돌아가는 함수가 아닙니다. fopen 은 시스템콜인 open 의 랩퍼일 뿐입니다. open 또한 유저 모드에서 하나의 함수일 뿐입니다. 그리고 그 open 이라는 함수가 트랩을 걸고, 커널이 ISR 을 통해서 그 요청을 처리하게 되어 있고 그 과정에서 VFS 과 연동이 일어납니다.

리눅스 커널 코드 자체가 OO 적으로 되어 있다는 것은 리눅스 소스 코드를 조금만 보신 분이라면 어느 정도는 OO 로 되어 있구나는 것을 아실 것입니다.

"또한 이 device라는 놈들은 실시간적으로 binding 되어야 하는 글자 그대로 동적 binding이 필요한 그런 구현이 되어야 한다는 것이지요.(insmod, rmmod)"

여기서 말씀하시는 동적 바인딩이라는게 대체 어떤 종류의 동적 바인딩을 말씀하시는 건지요? 여기서 동적 바인딩은 제가 아는 한에서는 동적 라이브러리와 다를 것이 하나도 없습니다. 아파치 모듈과 비슷한 개념이라는 뜻이지요. 그리고 insmod, rmmod 라고 옆에 적어 놓으셨는데, 커널의 모듈은 처음부터 정적으로 컴파일 될 수도 있습니다. 커널에서 어떤 함수를 호출하기 전 먼저 바이너티 코드를 메모리에 올린 뒤 함수 호출 하는 것 뿐입니다.

이런 과정을

"따라서 이것은 user interface적인 관점에서 보면 그냥 C함수이지만 구현입장에서 생각해보면 OO에서 말하는 pure virtual function이며 다시말해 Componant를 구현하기 위한 Interface역할을 의미합니다."

이렇게 말할 수 있을 지 의문이 듭니다. 구현을 위해 인터페이스가 통일되어 있다고는 볼 수 있을지 몰라도 과연 pure virtual function 이라고 할 수 있을까요? 애시당초 virtual function 이라는 것 자체가 OO 의 필수적인 개념조차 아니구요. 아니 오히려 상속자체가 OO 에서 필수적인 개념은 아니지요.

그리고 마지막 세 문장은 정말 해서는 안될 말씀입니다.

커널 소스코드 모르는 사람은 C 의 OOP 는 어렵다는 주장을 꺼내지도 못해야 됩니까? 근거가 커널 소스 코드에 그런 경향이 있다는 점 하나 때문에 상대를 이렇게 매몰차게 몰아부쳐도 되는지 모르겠습니다.

그리고 솔직히 님께서 말씀하신 커널에 대한 언급은 리눅스 커널 초보자인 제가 봐도 그다지 전문적으로 완벽한 언급은 아니었습니다.

익명 사용자의 이미지

김경태 wrote:

그러나...

fopen(), fread(), fwrite는 VFS에서 돌아가는 함수이며 이것은 device와 독립적인 system call입니다.

또한 이 device라는 놈들은 실시간적으로 binding 되어야 하는 글자 그대로 동적 binding이 필요한 그런 구현이 되어야 한다는 것이지요.(insmod, rmmod)

따라서 이것은 user interface적인 관점에서 보면 그냥 C함수이지만 구현입장에서 생각해보면 OO에서 말하는 pure virtual function이며 다시말해 Componant를 구현하기 위한 Interface역할을 의미합니다.

그런데 이것을 kernel에서는 C로 구현하고 있다는 겁니다.

결국 위의 VFS system call은 구현방법으로 보면 C로 OO의 pure virtual function을 성공적으로 구현한 것인데 이것은 C++로만 객체를 구현해야만 좋다는 논지에서 보면 이러한 LINUX의 kernel code는 그야말로 어설픈 객체 흉내내기에 불과한 쓰레기 코드가 되는 것이 아니냐고 되묻고 있는 겁니다.


음.. 3자 입장에서 볼때 뭔가 대화가 어긋나고 있는듯 합니다.

보통의 프로그래머들의 경우 시스템 레벨의 프로그래밍을 해야
할 경우라면 몰라도 상식적으로 커널코드까지 고려하지는
않습니다. 그리고 이런 보통 프로그래머의 입장에서 봤을때
system call을 단지 하나의 함수로 보는것은 비교적
자연스럽습니다.

이건 경태님이 시스템 레벨의 프로그래밍에 익숙해있거나..
또는 전문적으로 그 분야를 파고 들었기에 '일반적인 프로그래머'
들이 소유한 관점과는 조금 다른 관점을 소유하고 계심을
뜻합니다.

마치 일반인들은 타인의 얼굴을 그냥 자연스럽게 쳐다보지만...
피부과 의사들은 자신들의 주 전공이 피부 치료이기 때문에
타인의 얼굴을 볼적에 모공이나 피지상태, 주름정도, 유분함량등
까지도 정밀하게 뜯어보는것과 마찬가지 경우가 되겠습니다.

피부과 의사입장에서 피부가 세포로 이뤄져 있고..또 각질과
주름등이 얼굴에 상존해 있다는것을 지적할수는 있겠지만
이 설명만이 사람의 얼굴에 대한 올바른 설명일수 있다고
주장할수는 없는것이고.. 마찬가지로 일반인들이 얼굴을
살펴볼때 계란형이니.. 사각형이니..또는 피부가 검네..희네..
하는식의 나름대로 추상화된 설명을 제시하면서
이런 설명이 피부과 의사가 하는 디테일한 설명보다
더 옳다는 식으로 얘기할수도 없는것이죠.

앞서 얘기했듯이 설명의 수준이라는것이 존재하고...
각 레벨별로 설명은 그 나름의 의미를 갖습니다.

문제는 경태님과 이에 반대하시는 분이 프로그램을 보는
눈의 위치가 서로 달라서 서로 딴 소리를 있음에도...
각자의 위치에서 자신의 주장이 맞고 상대방은 틀렸다고
얘기하고 있다는거죠.

한분은 추상화수준을 너무 높게 설정해 두고 있고...
다른분은 너무 낮게 설정하고 있는 상황에서...
제 생각엔 서로 동일한것을 한가지 레벨만으로
설명할 수 있어야 한다는 도그마에 빠지신듯합니다.

제가 말씀드린대로 생각하면 논란이 될 이유가 하등에
없는 토픽인데... 왜 이렇게 엉뚱한 얘기들이 오가고 있는지
이해가 안가는군요.

gimmesilver의 이미지

x_bar wrote:

음.. 3자 입장에서 볼때 뭔가 대화가 어긋나고 있는듯 합니다.

저도 그렇게 느끼고 있습니다. 경태님이 말씀하시는 객체 지향과 제가 말하는 객체 지향은 서로 다른 것이었음을 이번 글을 보고 느꼈습니다.

Quote:

한분은 추상화수준을 너무 높게 설정해 두고 있고...
다른분은 너무 낮게 설정하고 있는 상황에서...
제 생각엔 서로 동일한것을 한가지 레벨만으로
설명할 수 있어야 한다는 도그마에 빠지신듯합니다.

제가 보기에는 경태님은 구현한 결과물이 '객체 지향'적인 것을 말씀하신 것 같고 저는 구현 방법이 '객체 지향'적인 것을 말하고 있었습니다.

김경태 wrote:

제가 파악한 바, 님의 한계는 진실로 C로 구현한 객체란 어떤 것인지 실제적인 예를 아직 한번도 제대로 검토한 적도 없으면서 일반적인 C사용에 대한 기초적인 상식과 C++의 문법이나 객체에 대한 몇가지 이론만 가지고 무조건 객체는 C++로만 구현해야 하고 C로 구현하면 제대로된 객체는 구현 불가능하다라고 말하고 있는 것입니다.

지피지기면 백전 백승이라는 말도 있는데 님께서는 계속 원론적인 부분만 말씀하시지 마시고 가령 위에 예로 들었던 C로 구현된 객체의 전형적인 예제인 VFS kernel source 정도만이라도 직접 분석해 보시고 나서 님의 주의 주장을 펴시는게 훨씬 더 현명해 보이는 것 같습니다.

상대방 주의 주장의 근거가 되는 kernel source나 그 체계가 뭔지 전혀 모르시는 상황에서 무조건 <객체는 C++로만 구현해야 제대로 된 객체다>라고 반복하신다면 그건 결국 일방적인 자기 주장일 뿐이므로 그 어떤 상대도 설득할 수 없지 않을런지요?

경태님이 말씀하시는 객체 지향과 제가 말씀드린 객체 지향은 관점이 서로 다른 것이었습니다. 그런데 그것을 제가 미쳐 파악하지 못하고 쓸데없이 논의를 길게 끌며 감정을 상하게 해드린 점 사과드립니다.
다만 한 가지만 수정드리자면 저는 C++로 '객체를 구현'해야 한다고 주장한 적은 없습니다. 단지 객체 지향 언어로 '객체 지향 프로그래밍'을 하는 것이 좋다라고 주장했을 뿐입니다. 오해가 없으시길 바랍니다.

------------------------
http://agbird.egloos.com

익명 사용자의 이미지

인용 : "단지 객체 지향 언어로 '객체 지향 프로그래밍'을 하는 것이 좋다라고 주장했을 뿐"

객체 지향언어로 객체 지향프로그래밍을 하는것이 좋다라고 주장하신것은 매우 의미없는말입니다.

비유해보자면 오토바이로 오토바이처럼 타는것이좋다. 혹은 자동차로 자동차터럼활용하는것이좋다 내지는

여자가 여자처럼행동하는것이 좋다. 뭐이런수준의 말인거죠..

그러나 보통의 이런논지를 꺼낸이들은 내심은 "특정언어만이 객체지향적이다" 라고 주장하고 싶은경우일겁니다.
또한 그렇게 비춰지지요.

위에 김경태님이쓴것은 사실은 그것이 객체지향적이 아니며 오히려 다른언어가 더 객체지향적이다라고 말하고 있는겁니다.

또한 시스템적인 세부내용까지 따지는것이 무의미하지 않으며 실체가 무엇인가를 아는것은 매우 중요하고

우리가 결론적으로 언어를선택함에있어 무엇이 중요한지를 따질수 있습니다.

즉, 눈에와닫는 문법적 현상만으로 객체지향적임판단할것인가 그렇다면 그것이 갖는의미는 무엇인지도 생각해봐야지요..

과연그것이 더편한가? 성능이 더좋은가? 실제롤 객체지향을 내세울때 성능이나 효율등을 내세웁니다.
그것이 실제로 사실이 아니거나. 그보다 더나은 언어나 방식이 이미 기존에 있다면요..
개발자가 실상은 모른체 너무 상술에 놀아나는건 아닌지..

심성현의 이미지

#include

typedef struct Person
{
int age;
} Person;

void Person_construct(Person *ob, int age)
{
ob->age = age;
}

void Person_destruct(Person *ob)
{
}

void Person_setage(Person *ob,int age)
{
ob->age = age;
}

int Person_getage(Person *ob)
{
return ob->age;
}

int main(int argc, char *argv[])
{
Person ob;
Person_construct(&ob, 3);

printf("%d\n", Person_getage(&ob));

Person_setage(&ob, 4);
printf("%d\n", Person_getage(&ob));

Person_destruct(&ob);

return 0;
}

cppig1995의 이미지

C++은 멀티패러다임 언어이기 때문에,
객체지향 언어인 Obj-C보다 우수하다고 주장합니다.
(적어도 비-OOP 분야에서 -_-;;; ㅈㅅ)

-명예의전당자료발굴단-

Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.

kalstein의 이미지

무슨 언어를 쓰는지는...개인적 취향이긴하지요...

하지만 똑같은 레벨로 잘 디자인이 됐다고 했을때...C와 C++은 많이 차이가 납니다.

위에...보니까 단순 멤버함수를 this포인터를 사용해서..예제를 들고있는데...

그건 C로도 물론 가능한 부분이지요.

자...그럼 C로 OOP를 하는것도 아무런 문제가 없다. 라고 주장하시는분들...

virtual member function들은 어찌 구현하시렵니까~~~

그리고 상속은요? 더불어 template는요? :)

전 요즘은...C++ 사고방식을 C언어로 표현해야되는 (업무가 C로 짜야될듯;;킁)

위기상황에 쳐해있어서 좀 안습이네요 ^^;;


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

익명사용자의 이미지

virtual의경우 다형성(upcasting)과 관련된 기능인데
기능구현은 별로 어렵지 않습니다.
template은 oop와 관계 없는 이야기입니다.
상속구현은 struct에 상위struct 부터 선언하면 되고
물론 폴리모피즘은 구현하기 어렵겠지만...
C로 거의 대부분가능하고 생각보다 어렵지 않으며 구조적 프로그래밍보다
코딩양이 줄때도 있습니다.

익명사용자의 이미지

폴리모피즘->다중상속

kalstein의 이미지

기능구현이야 할만한데요...

문제는 코드가 상당히 너저분해지겠죠...그리고 클래스 하나더 추가시에 기존 코드를 또 손봐야 할일이 생길테구요...

템플릿은 C++만의 (요즘은 슬슬 자바,C#쪽에서도 수용중..) 기능이니 제한다고 치고...

생성자, 소멸자의 자동호출기능은 어떻게 구현가능할까요...?

그게 가능하다면 C도 OOPL이 되는거겠죠. 덕분에 자원관리가 상당히 힘든것 아니겠습니까...

왠만한 메모리관리는 스마트포인터로 자동적으로 자바의 Garbage Collection보다 더 쉽고, 더 강력하게 사용가능한데 C 에서는 좀안된단말이죠 ㅎㅎ


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

익명사용자의 이미지

답글읽고나니 가능하다는걸 알았나보죠 ㅎㅎ

익명사용자의 이미지

추가 클래스 추가시 왜 기존코드를 손봐야 되죠 ㅎㅎ
부모가 바뀌는 일은 없어요 ㅎㅎ
바뀔일이 있다면 C++역시 바꿔야 될 부분이겠죠.
일단 C로 OOP한번 해보세요. 대부분이 잘못된 지식이라는 걸 알겁니다.

c++에 비하면 손이많이가는건 인정하죠

sohalee의 이미지

Glib, GObject를 이용해 C에서도 Object화 하는것과 생성자 소멸자등의 등록과 자동호출이 가능해집니다.
물론 가비지 컬렉터도 기본으로 지원합니다. g_object_ref와 g_object_unref는 레퍼런스 카운팅을 제어해줍니다.
C의 기본은 아니지만 리눅스라면 당연히 거의 glib은 사용하겠죠.
물론 allocation과 destory(free)가 malloc, free함수로 되는것은 아닙니다만 개발자 측면에서 그렇게 많이 다르진 않습니다.
물론 구조체와 함수로 이루어져 있으나 추상화, 상속등이 가능해 집니다 보통의 객체지향 언어와 구현하는것이 다를 뿐입니다.

keizie의 이미지

http://kldp.org/node/31629 - gtk와 객체지향에 대해 재미있는 쓰레드가 있습니다. 읽어보세요.

김상욱의 이미지

상당히 뒷북을 치고 있습니다만...

최초의 C++ 컴파일러는 C언어의 preprocessor로서 구현되었다고 알고있습니다.
즉 C++의 각종 메커니즘들이 macro 치환등을 통해서 완벽한 C언어로 바뀐 후, 기존의 C 컴파일러를 통해서 binary code화 된 것이죠.
저도 1990년에 이런 preprocessor 형 C++ 컴파일러를 써본적이 있습니다.

물론, 지금의 C++ 표준도 이런 preprocessor 형태로 처리 가능할지는 모르겠네요.

전웅의 이미지

> 최초의 C++ 컴파일러는 C언어의 preprocessor로서 구현되었다고 알고있습니다.

예, 맞습니다.

> 즉 C++의 각종 메커니즘들이 macro 치환등을 통해서 완벽한 C언어로 바뀐 후, 기존의 C 컴파일러를 통해서 binary code화 된 것이죠.
> 저도 1990년에 이런 preprocessor 형 C++ 컴파일러를 써본적이 있습니다.
>

preprocessor 라고 해서 C 언어에서 정의하는 preprocessor 를 의미한다기
보다는, 일단 (해당 환경에서) 번역 가능한 완전한 C 소스로 변환하는 중간
과정을 거쳐 binary code 를 생성했다는 것을 의미한다고 볼 수 있습니다.

> 물론, 지금의 C++ 표준도 이런 preprocessor 형태로 처리 가능할지는 모르겠네요.
>

따라서 지금의 C++ 표준도 동일한 행동을 보이는 C 프로그램으로 거쳐
binary code 를 생성하도록 구현될 수 있습니다 - 다만, 현실적인 이유로
다소(?) 뒤쳐지는 성능을 보이게 됩니다.

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

imyejin의 이미지

C로 번역했다가 바이너리 코드를 생성한다고 해서 꼭 뒤쳐지는 성능을 보이라는 법은 없지 않나요?
실제로 이런 방식으로 동작하는 상용 컴파일러가 있습니다.

http://www.comeaucomputing.com/

코드의 이식성을 위해 다른 컴파일러와 마찬가지로 중간 표현을 만들지만
그 후에 바이너리 코드를 만들기 위한 백엔드로는 C 컴파일러를 씁니다.
C++ -> 중간코드 -> C -> binary 이렇게 말이죠.

C++ 표준을 완전히 준수하며 C++ 의 모든 기능을 구현한다고 자랑하는 컴파일러인데요.
그럼 말씀하신 대로라면 다른 C++ 컴파일러들에 비해 특별히 comeau 컴파일러가 성능이 떨어지나요?
comeu 컴파일러를 염두해 두고 한 말씀인지 아니면 다른 성능이 안좋은 C++ 을 C 로 거쳐서 컴파일하는 컴파일러가 있는 건지요?

임예진 팬클럽 ♡예진아씨♡ http://cafe.daum.net/imyejin

[예진아씨 피카사 웹앨범] 임예진 팬클럽 ♡예진아씨♡ http://cafe.daum.net/imyejin

전웅의 이미지

> C로 번역했다가 바이너리 코드를 생성한다고 해서 꼭 뒤쳐지는 성능을 보이라는 법은 없지 않나요?
> 실제로 이런 방식으로 동작하는 상용 컴파일러가 있습니다.
>
> http://www.comeaucomputing.com/
>

:-) Comeau Computing 사 CEO 인 Greg Comeau 씨가 C/C++ 에 대한 지식이
상당한 분이죠. 예전엔 C 언어에 대한 깊이 있는 내용을 놓고 메일도 한참
주고 받았었는데, 요즘은 C++ 위원회 활동만 하시는지 C 언어 쪽에서는
뵙기 힘들더군요.

> 코드의 이식성을 위해 다른 컴파일러와 마찬가지로 중간 표현을 만들지만
> 그 후에 바이너리 코드를 만들기 위한 백엔드로는 C 컴파일러를 씁니다.
> C++ -> 중간코드 -> C -> binary 이렇게 말이죠.
>
> C++ 표준을 완전히 준수하며 C++ 의 모든 기능을 구현한다고 자랑하는 컴파일러인데요.
> 그럼 말씀하신 대로라면 다른 C++ 컴파일러들에 비해 특별히 comeau 컴파일러가 성능이 떨어지나요?
> comeu 컴파일러를 염두해 두고 한 말씀인지 아니면 다른 성능이 안좋은 C++ 을 C 로 거쳐서 컴파일하는 컴파일러가 있는 건지요?
>

님께서 (제가 보기엔) 정신없는 이미지를 시그너쳐에 쓰시는 것이 님 자유
이듯, 답변을 드리는 것도 제 자유겠지요? 정신없이 움직이는 아리따운
아주머니 이미지가 안 보이는 날 답변 드리겠습니다.

그럼...

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

sohalee의 이미지

Glib과 GObject는 다들 아실것입니다.
GObject를 알고 GObject의 타입 등록 방식을 이해하시면 새로운 타입을 만들어 등록하고 그것을 상속, 생성, 제거가 가능합니다. 레퍼런스 카운팅도 해줍니다. 개념적으로는 객체지향을 거의 구현 가능하나 다중상속에서는 문제가 좀 생기겠군요.
일단 기본적으로 상속, 추상화는 구현 방식만 다를 뿐 제대로 되며 가비지 컬렉터도 작동합니다.
구조체를 이용하는등 방식 실제 내부적으로 작동하는것은 위에 다른 분들이 잘 설명해주셧고 C만으로의 한계는 GObject로 어느정도 극복이 가능해집니다. 예를 들자먼 위에서 어떤분이 말씀해주신 생성자, 소멸자 자동호출도 해줍니다.
GObject라는놈이 자바의 Object클래스 같은놈입니다.

GTK가 GObject를 이용해 C로 객체지향을 구현한 대표적인 예라고 할 수 있겠지요.

아래 간단한 예제를 보여드리죠. 현재 제가 RDBMS관리툴을 만드는 것중 일부입니다.

-- 아래의 것들은 이런식으로 사용이 가능해지니다.

OtDbConnection *conn = ot_db_connection_cub_new (...); // OtDbConnection을 상속받아 구현한 cubrid용 구현체
ot_db_connection_connect (conn); // 구현된 바에 따르면 OtDbConnection의 class를 이놈을 상속받은 OtDbConnectionCub의 class로 변환한뒤 실제로 구현체의 함수를 실행합니다. OtDbConnectionClass의 connect에 등록된 함수 실행
g_object_unref (connn0; // 레퍼런스 카운팅 -1

-- 먼저 추상 헤더

#define OT_TYPE_DB_CONNECTION               (ot_db_connection_get_type ())
#define OT_DB_CONNECTION(object)            (G_TYPE_CHECK_INSTANCE_CAST ((object), OT_TYPE_DB_CONNECTION, OtDbConnection))
#define OT_DB_CONNECTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), OT_TYPE_DB_CONNECTION, OtDbConnectionClass))
#define OT_IS_DB_CONNECTION(object)         (G_TYPE_CHECK_INSTANCE_TYPE ((object), OT_TYPE_DB_CONNECTION))
#define OT_IS_DB_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), OT_TYPE_DB_CONNECTION))
#define OT_DB_CONNECTION_GET_CLASS(object)  (G_TYPE_INSTANCE_GET_CLASS ((object), OT_TYPE_DB_CONNECTION, OtDbConnectionClass))
 
 
typedef struct _OtDbConnection      OtDbConnection;
typedef struct _OtDbConnectionClass OtDbConnectionClass;
 
struct _OtDbConnection
{
    GInitiallyUnowned parent_instance;
 
    gchar   *url;
    gchar   *username;
    gchar   *password;
    gchar   *encoding;
 
    gint fetch_size;
 
    GPtrArray       *req_columns;       // <OtDbColumn>
    OtDbStmtType     req_stmt_type;
    gint             req_modify_count;
    gint             req_cursor_index;
};
 
struct _OtDbConnectionClass
{
    GInitiallyUnownedClass parent_class;
 
    OtDbConnection* (*new_clone)                (OtDbConnection *connection);
    gboolean        (*connect)                  (OtDbConnection *connection);
    gboolean        (*disconnect)               (OtDbConnection *connection);
    gboolean        (*is_connected)             (OtDbConnection *connection);
    gpointer        (*get_conn_handle)          (OtDbConnection *connection);
    gchar*          (*dup_current_err_msg)      (OtDbConnection *connection);
    gboolean        (*prepare)                  (OtDbConnection *connection, const gchar *query);
    OtDbParamErr    (*set_param)                (OtDbConnection *connection, gint index,
                                                 OtDbCType ctype, gpointer dbtype,
                                                 gpointer value, gint length);
    gboolean        (*execute)                  (OtDbConnection *connection);
    gboolean        (*result_next)              (OtDbConnection *connection);
    gboolean        (*req_close)                (OtDbConnection *connection);
    GPtrArray*      (*dup_result_data)          (OtDbConnection *connection);
    GPtrArray*      (*dup_table_name_list)      (OtDbConnection *connection, OtDbTableType table_type);
    GPtrArray*      (*dup_index_name_list)      (OtDbConnection *connection);
    GPtrArray*      (*dup_procedure_name_list)  (OtDbConnection *connection);
    GPtrArray*      (*dup_column_list)          (OtDbConnection *connection, const gchar *table_name);
    gchar*          (*dup_simple_sql_select)    (OtDbConnection *connection, const gchar *table_name,
                                                 GPtrArray *fields, GPtrArray *orders);
};
 
GType           ot_db_connection_get_type                   (void);
GPtrArray*      ot_db_connection_get_req_columns            (OtDbConnection *connection);
void            ot_db_connection_set_url                    (OtDbConnection *connection,
                                                             const gchar    *url);
...
...
...

-- 그다음 추상 소스

static gpointer parent_class = NULL;
 
static void
ot_db_connection_dispose (GObject *gobject)
{
    OtDbConnection *connection = OT_DB_CONNECTION (gobject);
 
    if (connection->url != NULL)
    {
        g_free (connection->username);
        connection->username = NULL;
    }
 
    if (connection->username != NULL)
    {
        g_free (connection->username);
        connection->username = NULL;
    }
 
    if (connection->password != NULL)
    {
        g_free (connection->password);
        connection->password = NULL;
    }
 
    if (connection->encoding != NULL)
    {
        g_free (connection->encoding);
        connection->encoding = NULL;
    }
 
    ot_db_connection_clear_req_columns (connection);
 
    G_OBJECT_CLASS (parent_class)->dispose (gobject);
}
 
static void
ot_db_connection_base_class_init (OtDbConnectionClass *class)
{
}
 
static void
ot_db_connection_base_class_finalize (OtDbConnectionClass *class)
{
}
 
static void
ot_db_connection_class_init (OtDbConnectionClass *class)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
    parent_class = g_type_class_ref (G_TYPE_OBJECT);
 
    gobject_class->dispose = ot_db_connection_dispose;
 
    class->new_clone                = NULL;
    class->connect                  = NULL;
    class->disconnect               = NULL;
    class->is_connected             = NULL;
    class->get_conn_handle          = NULL;
    class->dup_current_err_msg      = NULL;
    class->prepare                  = NULL;
    class->set_param                = NULL;
    class->execute                  = NULL;
    class->result_next              = NULL;
    class->req_close                = NULL;
    class->dup_result_data          = NULL;
    class->dup_table_name_list      = NULL;
    class->dup_index_name_list      = NULL;
    class->dup_procedure_name_list  = NULL;
    class->dup_column_list          = NULL;
    class->dup_simple_sql_select    = NULL;
}
 
static void
ot_db_connection_init (OtDbConnection       *connection,
                       OtDbConnectionClass  *class)
{
    connection->url                 = NULL;
    connection->username            = NULL;
    connection->password            = NULL;
    connection->encoding            = NULL;
    connection->fetch_size          = 0;
    connection->req_columns         = NULL;
    connection->req_stmt_type       = OT_DB_STMT_TYPE_NONE;
    connection->req_modify_count    = 0;
    connection->req_cursor_index    = 0;
}
 
GType
ot_db_connection_get_type (void)
{
    static GType object_type = 0;
 
    if (!object_type)
    {
        const GTypeInfo object_info =
        {
            sizeof (OtDbConnectionClass),
            (GBaseInitFunc) ot_db_connection_base_class_init,
            (GBaseFinalizeFunc) ot_db_connection_base_class_finalize,
            (GClassInitFunc) ot_db_connection_class_init,
            NULL,       /* class_finalize */
            NULL,       /* class_data */
            sizeof (OtDbConnection),
            16,     /* n_preallocs */
            (GInstanceInitFunc) ot_db_connection_init,
            NULL,       /* value_table */
        };
 
        object_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, "OtDbConnection", 
                &object_info, G_TYPE_FLAG_ABSTRACT);
    }
 
    return object_type;
}
 
...
...
 
OtDbConnection*
ot_db_connection_new_clone (OtDbConnection *connection)
{
    OtDbConnectionClass *class = OT_DB_CONNECTION_GET_CLASS (connection);
 
    return class->new_clone (connection);
}
 
 
gboolean
ot_db_connection_connect (OtDbConnection *connection)
{
    OtDbConnectionClass *class = OT_DB_CONNECTION_GET_CLASS (connection);
 
    return class->connect (connection);
}
 
gboolean
ot_db_connection_disconnect (OtDbConnection *connection)
{
    OtDbConnectionClass *class = OT_DB_CONNECTION_GET_CLASS (connection);
 
    return class->disconnect (connection);
}
 
gboolean
ot_db_connection_is_connected (OtDbConnection *connection)
{
    OtDbConnectionClass *class = OT_DB_CONNECTION_GET_CLASS (connection);
 
    return class->is_connected (connection);
}
 
...
...

-- 아래는 구현체 헤더

#define OT_TYPE_DB_CONNECTION_CUB               (ot_db_connection_cub_get_type ())
#define OT_DB_CONNECTION_CUB(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), OT_TYPE_DB_CONNECTION_CUB, OtDbConnectionCub))
#define OT_DB_CONNECTION_CUB_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), OT_TYPE_DB_CONNECTION_CUB, OtDbConnectionCubClass))
#define OT_IS_DB_CONNECTION_CUB(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OT_TYPE_DB_CONNECTION_CUB))
#define OT_IS_DB_CONNECTION_CUB_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), OT_TYPE_DB_CONNECTION_CUB))
#define OT_DB_CONNECTION_CUB_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), OT_TYPE_DB_CONNECTION_CUB, OtDbConnectionCubClass))
 
 
typedef struct _OtDbConnectionCub      OtDbConnectionCub;
typedef struct _OtDbConnectionCubClass OtDbConnectionCubClass;
 
struct _OtDbConnectionCub
{
    OtDbConnection  connection;
 
    gint     conn_handle;
    gint     req_handle;
    gint     err_code;
    gchar   *err_msg;
 
    gchar   *host;
    gint     port;
    gchar   *database;
};
 
struct _OtDbConnectionCubClass
{
    OtDbConnectionClass parent_class;
};
 
GType           ot_db_connection_cub_get_type   (void);
OtDbConnection* ot_db_connection_cub_new        (const gchar    *url,
                                                 const gchar    *username,
                                                 const gchar    *password,
                                                 const gchar    *encoding);

-- 아래는 구현체 소스입니다.

static OtDbConnectionClass *ot_db_connection_cub_parent_class = NULL;
 
static void
ot_db_connection_cub_dispose (GObject *gobject)
{
    OtDbConnectionCub *connection_cub = OT_DB_CONNECTION_CUB (gobject);
 
    if (connection_cub->err_msg != NULL)
    {
        g_free (connection_cub->err_msg);
        connection_cub->err_msg = NULL;
    }
 
    if (connection_cub->host != NULL)
    {
        g_free (connection_cub->host);
        connection_cub->host = NULL;
    }
 
    if (connection_cub->database != NULL)
    {
        g_free (connection_cub->database);
        connection_cub->database = NULL;
    }
 
    G_OBJECT_CLASS (ot_db_connection_cub_parent_class)->dispose (gobject);
}
 
static OtDbConnection*
ot_db_connection_cub_new_clone (OtDbConnection *connection)
{
    return ot_db_connection_cub_new (connection->url, connection->username,
            connection->password, connection->encoding); 
}
 
 
static gboolean
ot_db_connection_cub_connect (OtDbConnection *connection)
{
    OtDbConnectionCub   *connection_cub = OT_DB_CONNECTION_CUB (connection);
    OtDbConnectionClass *class          = OT_DB_CONNECTION_GET_CLASS (connection);
    gint                 conn_handle    = 0;
    gint                 res            = 0;
 
    if (class->is_connected (connection))
    {
        // TODO : luna 국제화
        g_debug ("이미 연결 핸들이 만들어져 있습니다. 다시 만들지 않습니다.");
        return TRUE;
    }
 
    ot_db_connection_cub_err_init (connection_cub);
 
    conn_handle = cci_connect (connection_cub->host, connection_cub->port,
            connection_cub->database, connection->username, connection->password);
    if (conn_handle < 0)
    {
        switch (conn_handle)
        {
            // TODO : luna 국제화
            case CCI_ER_NO_MORE_MEMORY:
                connection_cub->err_msg = g_strdup ("메모리가 부족합니다.");
            break;
 
            case CCI_ER_HOSTNAME:
                connection_cub->err_msg = g_strdup ("해당 호스트에 연결할 수 없습니다.");
            break;
 
            default:
                connection_cub->err_msg = g_strdup ("알려지지 않은 오류가 발생하였습니다.");
            break;
        }
 
        connection_cub->err_code = conn_handle;
 
        return FALSE;
    }
 
    /* 접속 테스트 */
    res = cci_get_db_version (conn_handle, NULL, 0);
    if (res < 0)
    {
        connection_cub->err_msg = g_strdup ("접속 실패. 접속정보를 확인하여 주십시요");
        // 무조건 disconnect를 실행하고 에러는 무시한다.
        cci_disconnect (conn_handle, NULL);
 
        g_debug ("connection test fail");
 
        return FALSE;
    }
 
    connection_cub->conn_handle = conn_handle;
 
    return TRUE;
}
 
...
...
 
 
static void
ot_db_connection_cub_class_init (OtDbConnectionCubClass *class)
{
    GObjectClass        *gobject_class  = G_OBJECT_CLASS (class);
    OtDbConnectionClass *cclass         = OT_DB_CONNECTION_CLASS (class);
 
    ot_db_connection_cub_parent_class = g_type_class_peek_parent (class);
 
    gobject_class->dispose = ot_db_connection_cub_dispose;
 
    cclass->new_clone               = ot_db_connection_cub_new_clone;
    cclass->connect                 = ot_db_connection_cub_connect;
    cclass->disconnect              = ot_db_connection_cub_disconnect;
    cclass->is_connected            = ot_db_connection_cub_is_connected;
    cclass->get_conn_handle         = ot_db_connection_cub_get_conn_handle;
    cclass->dup_current_err_msg     = ot_db_connection_cub_dup_current_err_msg;
    cclass->prepare                 = ot_db_connection_cub_prepare;
    cclass->set_param               = ot_db_connection_cub_set_param;
    cclass->execute                 = ot_db_connection_cub_execute;
    cclass->result_next             = ot_db_connection_cub_result_next;
    cclass->req_close               = ot_db_connection_cub_req_close;
    cclass->dup_result_data         = ot_db_connection_cub_dup_result_data;
    cclass->dup_table_name_list     = ot_db_connection_cub_dup_table_name_list;
    cclass->dup_column_list         = ot_db_connection_cub_dup_column_list;
    cclass->dup_index_name_list     = ot_db_connection_cub_dup_index_name_list;
    cclass->dup_procedure_name_list = ot_db_connection_cub_dup_procedure_name_list;
    cclass->dup_simple_sql_select   = ot_db_connection_cub_dup_simple_sql_select;
}
 
static void
ot_db_connection_cub_init (OtDbConnectionCub *connection)
{
    connection->conn_handle = 0;
    connection->req_handle  = 0;
    connection->err_code    = 0;
    connection->err_msg     = NULL;
 
    connection->host        = NULL;
    connection->port        = -1;
    connection->database    = NULL;
}
 
GType
ot_db_connection_cub_get_type (void)
{
    static GType widget_type = 0;
 
    if (G_UNLIKELY (widget_type == 0))
    {
        const GTypeInfo widget_info =
        {
            sizeof (OtDbConnectionCubClass),
            NULL,       /* base_init */
            NULL,
            (GClassInitFunc) ot_db_connection_cub_class_init,
            NULL,       /* class_finalize */
            NULL,       /* class_data */
            sizeof (OtDbConnectionCub),
            0,          /* n_preallocs */
            (GInstanceInitFunc) ot_db_connection_cub_init,
            NULL,       /* value_table */
        };
        widget_type = g_type_register_static (OT_TYPE_DB_CONNECTION, "OtDbConnectionCub",
                &widget_info, 0);
    }
 
    return widget_type;
}
 
 
 
/*
 * public
 */
 
OtDbConnection*
ot_db_connection_cub_new (const gchar   *url,
                          const gchar   *username,
                          const gchar   *password,
                          const gchar   *encoding)
{
    OtDbConnectionCub *connection = OT_DB_CONNECTION_CUB (
            g_object_new (OT_TYPE_DB_CONNECTION_CUB, NULL));
    // 위 까지 하면 instance init와 base init등이 모두 자동으로 실행됩니다.
 
...
...
 
    return OT_DB_CONNECTION (connection);
}
 
...
...

김일영의 이미지

사실 C에서도 클래스와 비슷한 자료형 얼마든지 만들 수 있습니다.
그렇게 쓰는 것이 좀 불편할지는 몰라도 규칙적으로 사용하면 별 문제 안됩니다.
그리고 개체지향적 설계를 C로 구현하는 것 얼마든지 가능하고 미련하거나 무의미한게 아닙니다.
콜백 개념을 사용하는 C 라이브러리들 중엔 this 포인터와 같은 개념을 구현하는 것들도 있습니다.

오히려 개체지향 언어를 사용해야 하는 이유는 따로 있습니다.
상속체계에 따른 형변환 규칙을 적용해준다는 것이죠.
부모 클래스의 변수에 자식 클래스의 인스턴스를 대입할 수는 있지만 다른 것은 막아준다는것.
이걸 통해서 강력한 형 검사를 하면서도 상속의 개념을 그대로 사용할 수 있는거죠.

C에서는 그런 것이 안되기 때문에 강제 형변환을 통해서 강력한 형 검사를 항상 무력화시킬 수 밖에 없는데
그로 인해서 컴파일 시에 잡아야 할 에러들을 잡지 못하게 됩니다. 경험상 이게 가장 큰 문제더군요.

sohalee의 이미지

vi를 쓰거나 보통의 텍스트에디터라면 맞는말씀입니다. 사실상 개발자에겐 매우 불편한 일이 아닐수 없습니다.
그래서 저는 eclipse에 CDT를 붙여서 씁니다.
코드 작성중 에디터 상에서 이미 에러와 경고를 모두 보여줍니다. 타입 캐스팅에 관련된 부분도 알려줍니다.
CDT가 아직은 말이 많지만 그래도 vi등을 개발하던 사람에겐 매우 훌륭한 도구임에 틀림없습니다.
자바처럼 빌드를 자동으로 해주는 기능도 가지고있구요. 도구로 그문제를 해결하고 있습니다.
도구의 도움없이 쓰기에는 개발자가 신경을 써야하는것이 불편한건 맞습니다.

김일영의 이미지

이클립스를 거의 안쓰다 보니 CDT라는 것을 잘 모르겠군요.
어떤 도구이고 어디서 구하고 어떻게 쓰는건지...
정보를 좀 주시면 고맙겠습니다.

sohalee의 이미지

http://www.eclipse.org/ eclipse는 여기서

http://www.eclipse.org/cdt/downloads.php CDT는 여기서

CDT는 eclipse용 plug-in이며 C/C++ 개발을 위한것입니다.

컴파일러가 내줄수 있는 오류나 경고는 에디터 상에서도 대부분 볼수 있습니다.
물론 강제로 형변화 시켜버린것까지 오류를 내주거나 하진 않습니다. 아마 컴파일러 수준의 경고나 오류정도인것 같습니다.
다만 말씀하셨던 관련없는 타입간의 대입문제정도는 경고로 쉽게 볼수 있습니다.
단지 오류나 경고 표시가 문제가 아니고 이클립스와 CDT를 합쳐 쓰시다보면 개발중에 매번 컴파일 할 필요도 없고
타입은 잘 안써서 모르겠으나 Ctrl + 마우스 좌클릭으로 함수정도는 찾아가줍니다.
잘 아시겠지만 eclipse의 CVS나 SVN같은 플러그인을 그대로 이용할수 있다보니 개발하기 매우 편리합니다.
저도 주로 쓰는 기능은 그정도라 쿨럭 -0-

김일영의 이미지

좋은 정보 감사합니다.
즐코 하시길~

익명 사용자의 이미지

C로도 물론 할 수 있지만 C++같은 것이 장점이 될 수 있는 또 다른 이유는...

C++과 같이 객체지향을 언어설계에서부터 염두에 둔 언어는
객체지향과 관련하여 최적화할 수 있다는 것이죠.

예를 들어 GObject는 어떠한 객체지향적 최적화를 할 수 없지만
C++의 그것은 inline member function이라던지 기타 class관련 최적화를
언어를 설계할때나 컴파일러를 제작할때 미리 염두에 둘 수 있죠.

뭐 C로 하려면 할 수 있지만 C++로 하는 가장 큰 이유는
소스의 양이 대폭 줄어든다는 점이겠지만요. ^^

익명 사용자의 이미지

inline member function말고 더 깊이 있는
다른 예를 들어보자면 RVO 같은 걸 들 수 있겠죠.
http://kldp.org/node/73060#comment-343448

뭐 C로 삽질해도 할 수 있겠지만 C++로 하는 가장 큰 이유는
소스의 양이 대폭 줄어든다는 점이겠지만요. ^^

juami의 이미지

제가 딱 그런 환경인데요..
WIPI-C/BREW/WIN32/WINCE/LINUX/기타 NON-OS환경 약간..
에서 같은 코드를 돌려야 합니다.
환경의 제약으로 인하여 C++의 기능을 다 못쓰는 경우가 많아서 C++의 기능을 제대로 쓰기가 어렵습니다.
그런데 설계상의 편의때문에 OO적인 설계를 하였습니다.
이런경우 C를 써야하는 절차적인 설계를 해야 할까요?
그래서 저도 위에 설명된 방식으로 상속이나 virtual method등을 구현하여 사용합니다.
무조건 C++이나 OOPL을 써야 한다고 말하기에는 좀 그렇군요.

knight2000의 이미지

C++에서 구현할 수 있는 것은 C에서도 구현할 수 있습니다.
(조금만 생각하면 당연한 것일 수도... ^^a)

===== ===== ===== ===== =====
knight2000 of SALM.
SALM stood for SALM Ain't a Life Model.
SALM is not the life model, but SALM is just the life.

===== ===== ===== ===== =====
knight2000 of SALM.
SALM stood for SALM Ain't a Life Model.
SALM is not the life model, but SALM is just the life.

Scarecrow의 이미지

template metaprogramming은
plain C로 어떻게 해야할지 많이 생각해봐도 잘 모르겠군요.

#define으로는 recursion이 안되니까 말이죠...

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.