답변
예. 실제로 Axel Schreiner는 자신의 저서 “ANSI-C의 객체 지향 프로그래밍”을 무료로 제공하며이 주제를 매우 철저히 다루고 있습니다.
답변
다형성에 대해 이야기하고 있기 때문에 C ++이 나오기 몇 년 전에 그런 일을하고있었습니다.
기본적으로 a struct
를 사용 하여 데이터와 함수 포인터 목록을 모두 보유하여 해당 데이터의 관련 기능을 가리 킵니다.
따라서 통신 클래스에서는 객체에 대한 데이터와 함께 구조에서 4 개의 함수 포인터로 유지되는 공개, 읽기, 쓰기 및 닫기 호출이 있습니다.
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And data goes here.
} tCommClass;
tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;
tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;
물론, 위의 코드 세그먼트는 실제로 다음과 같은 “생성자”에 있습니다 rs232Init()
.
해당 클래스에서 ‘상속’할 때 포인터를 자신의 함수를 가리 키도록 변경하면됩니다. 이러한 함수를 호출 한 사람은 모두 함수 포인터를 통해 다형성을 얻을 수 있습니다.
int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");
수동 vtable과 같습니다.
포인터를 NULL로 설정하여 가상 클래스를 가질 수도 있습니다. 동작은 C ++ (컴파일 타임 오류가 아니라 런타임시 코어 덤프)과 약간 다릅니다.
다음은이를 보여주는 샘플 코드입니다. 먼저 최상위 클래스 구조 :
#include <stdio.h>
// The top-level class.
typedef struct sCommClass {
int (*open)(struct sCommClass *self, char *fspec);
} tCommClass;
그런 다음 TCP ‘subclass’에 대한 함수가 있습니다.
// Function for the TCP 'class'.
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
그리고 HTTP도 마찬가지입니다 :
// Function for the HTTP 'class'.
static int httpOpen (tCommClass *http, char *fspec) {
printf ("Opening HTTP: %s\n", fspec);
return 0;
}
static int httpInit (tCommClass *http) {
http->open = &httpOpen;
return 0;
}
마지막으로 테스트 프로그램이 실제로 작동하는지 보여줍니다.
// Test program.
int main (void) {
int status;
tCommClass commTcp, commHttp;
// Same 'base' class but initialised to different sub-classes.
tcpInit (&commTcp);
httpInit (&commHttp);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHttp.open)(&commHttp, "http://www.microsoft.com");
return 0;
}
출력이 생성됩니다.
Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com
하위 클래스에 따라 다른 함수가 호출되고 있음을 알 수 있습니다.
답변
네임 스페이스는 종종 다음을 수행하여 수행됩니다.
stack_push(thing *)
대신에
stack::push(thing *)
C 구조체를 C ++ 클래스 와 같은 것으로 만들려면 다음을 수행하십시오.
class stack {
public:
stack();
void push(thing *);
thing * pop();
static int this_is_here_as_an_example_only;
private:
...
};
으로
struct stack {
struct stack_type * my_type;
// Put the stuff that you put after private: here
};
struct stack_type {
void (* construct)(struct stack * this); // This takes uninitialized memory
struct stack * (* operator_new)(); // This allocates a new struct, passes it to construct, and then returns it
void (*push)(struct stack * this, thing * t); // Pushing t onto this stack
thing * (*pop)(struct stack * this); // Pops the top thing off the stack and returns it
int this_is_here_as_an_example_only;
}Stack = {
.construct = stack_construct,
.operator_new = stack_operator_new,
.push = stack_push,
.pop = stack_pop
};
// All of these functions are assumed to be defined somewhere else
그리고 :
struct stack * st = Stack.operator_new(); // Make a new stack
if (!st) {
// Do something about it
} else {
// You can use the stack
stack_push(st, thing0); // This is a non-virtual call
Stack.push(st, thing1); // This is like casting *st to a Stack (which it already is) and doing the push
st->my_type.push(st, thing2); // This is a virtual call
}
소멸자 또는 삭제하지 않았지만 동일한 패턴을 따릅니다.
this_is_here_as_an_example_only는 유형의 모든 인스턴스에서 공유되는 정적 클래스 변수와 같습니다. 일부는 이것을 취하는 것을 제외하고는 모든 메소드는 실제로 정적입니다 *
답변
C에서 OOP를 구현하는 것은 OOP를 구현하는 것이 OOP를 배우고 내부 작업을 이해 하는 훌륭한 방법이라고 생각합니다 . 많은 프로그래머의 경험에 따르면 기술을 효율적이고 자신있게 사용하려면 프로그래머가 기본 개념이 어떻게 구현되는지 이해해야합니다. C에서 클래스, 상속 및 다형성을 에뮬레이트하면 바로 이것을 가르칩니다.
원래 질문에 대답하기 위해 C에서 OOP를 수행하는 방법을 가르치는 몇 가지 자료가 있습니다.
EmbeddedGurus.com 블로그 게시물 “C의 객체 기반 프로그래밍”은 이식 가능한 C에서 클래스 및 단일 상속을 구현하는 방법을 보여줍니다.
http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c /
애플리케이션 노트 “”C + “-C의 객체 지향 프로그래밍”은 전 처리기 매크로를 사용하여 C에서 클래스, 단일 상속 및 후기 바인딩 (다형성)을 구현하는 방법을 보여줍니다 (
http://www.state-machine.com/resources/cplus_3). 0_manual.pdf 의 예제 코드는 http://www.state-machine.com/resources/cplus_3.0.zip 에서 볼 수 있습니다 .
답변
나는 그것을 보았다. 나는 그것을 추천하지 않을 것입니다. C ++은 원래 C 코드를 중간 단계로 생성하는 전처리기로 시작되었습니다.
본질적으로 당신이하는 일은 함수 참조를 저장하는 모든 메소드에 대한 디스패치 테이블을 만드는 것입니다. 클래스를 파생 시키려면이 디스패치 테이블을 복사하고 재정의하려는 항목을 대체하고 새 “메소드”가 기본 메소드를 호출하려는 경우 원래 메소드를 호출해야합니다. 결국 C ++을 다시 작성하게됩니다.