programing

C에서는 객체 지향 코드를 어떻게 쓸 수 있을까요?

sourcetip 2022. 7. 16. 08:59
반응형

C에서는 객체 지향 코드를 어떻게 쓸 수 있을까요?

오브젝트 지향 코드를 C로 작성하는 방법에는 어떤 것이 있습니까?특히 다형성에 관해서는요.


C 의 「스택 오버플로우」질문 「객체 방향」을 참조해 주세요.

C++가 나오기 몇 년 전부터다형성에 대해 이야기하고 있었으니 할 수 있어요

으로는 ★★★★★★★★★를 사용합니다.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");

수동 테이블 같은 거요

포인터를 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

서브클래스에 따라 다른 함수가 호출되는 것을 알 수 있습니다.

네. 사실 액셀 슈라이너는 의 책 "ANSI-C의 객체 지향 프로그래밍"을 무료로 제공하고 있는데, 이 책은 이 주제를 상당히 철저하게 다루고 있습니다.

네임스페이스는 보통 다음과 같이 수행합니다.

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_instatic_only는 정적 클래스 변수와 비슷하며 유형의 모든 인스턴스에서 공유됩니다.모든 메서드는 실제로 스태틱합니다.단, 일부 메서드는 이 *를 사용합니다.

저는 OOP를 C로 구현하는 것 자체가 유용한 것 외에 OOP를 배우고 그 내부를 이해하는 훌륭한 방법이라고 생각합니다.많은 프로그래머의 경험에 따르면, 효율적이고 자신 있게 기술을 사용하기 위해서는 프로그래머가 기본 개념들이 궁극적으로 어떻게 구현되는지를 이해해야 합니다.C의 클래스, 상속, 다형성을 에뮬레이트하면 이것만 알 수 있습니다.

첫 번째 질문에 답하기 위해 C에서 OOP를 실행하는 방법을 알려주는 몇 가지 리소스를 소개합니다.

EmbeddedGurus.com 블로그 투고 "Object-based programming in 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++를 다시 쓰게 됩니다.

함수 포인터를 사용하여 가짜로 만들 수 있으며, 사실 C++ 프로그램을 C로 컴파일하는 것은 이론적으로 가능하다고 생각합니다.

그러나 패러다임을 사용하는 언어를 선택하는 것보다 언어에 패러다임을 강요하는 것은 거의 말이 되지 않는다.

물론 가능합니다.이것이 GTK+ GNOME의 모든 기반이 되는 프레임워크인 GObject가 하는 일입니다.

네, 가능합니다.C++나 Objective-C가 등장하기 전에 사람들은 객체 지향 C를 쓰고 있었다.C++와 Objective-C는 모두 부분적으로 C에서 사용된 OO 개념의 일부를 언어의 일부로 공식화하려고 시도했다.

여기에서는 메서드 호출처럼 보이는 것을 만드는 방법을 보여 주는 매우 간단한 프로그램을 소개합니다(더 나은 방법이 있습니다).이는 언어가 개념을 지원하는 증거일 뿐입니다.)

#include<stdio.h>

struct foobarbaz{
    int one;
    int two;
    int three;
    int (*exampleMethod)(int, int);
};

int addTwoNumbers(int a, int b){
    return a+b;
}

int main()
{
    // Define the function pointer
    int (*pointerToFunction)(int, int) = addTwoNumbers;

    // Let's make sure we can call the pointer
    int test = (*pointerToFunction)(12,12);
    printf ("test: %u \n",  test);

    // Now, define an instance of our struct
    // and add some default values.
    struct foobarbaz fbb;
    fbb.one   = 1;
    fbb.two   = 2;
    fbb.three = 3;

    // Now add a "method"
    fbb.exampleMethod = addTwoNumbers;

    // Try calling the method
    int test2 = fbb.exampleMethod(13,36);
    printf ("test2: %u \n",  test2);

    printf("\nDone\n");
    return 0;
}

동물과 개: C++의 vtable.도 구분합니다.Alloc, Animal_New)는 malloc()로 지정합니다..this인터를를돌돌돌

가상 이외의 기능을 실행하는 경우, 이것은 3가지 기능입니다.하지 않고 는 vtable이 없습니다.this」에서는 으로 애매한 문제를 하기 위해서 복수의 합니다.일반적으로 여러 상속을 수행하려면 여러 vtable이 필요합니다.

또한 예외 처리를 수행하려면 setjmp/longjmp를 사용할 수 있어야 합니다.

struct Animal_Vtable{
    typedef void (*Walk_Fun)(struct Animal *a_This);
    typedef struct Animal * (*Dtor_Fun)(struct Animal *a_This);

    Walk_Fun Walk;
    Dtor_Fun Dtor;
};

struct Animal{
    Animal_Vtable vtable;

    char *Name;
};

struct Dog{
    Animal_Vtable vtable;

    char *Name; // Mirror member variables for easy access
    char *Type;
};

void Animal_Walk(struct Animal *a_This){
    printf("Animal (%s) walking\n", a_This->Name);
}

struct Animal* Animal_Dtor(struct Animal *a_This){
    printf("animal::dtor\n");
    return a_This;
}

Animal *Animal_Alloc(){
    return (Animal*)malloc(sizeof(Animal));
}

Animal *Animal_New(Animal *a_Animal){
    a_Animal->vtable.Walk = Animal_Walk;
    a_Animal->vtable.Dtor = Animal_Dtor;
    a_Animal->Name = "Anonymous";
    return a_Animal;
}

void Animal_Free(Animal *a_This){
    a_This->vtable.Dtor(a_This);

    free(a_This);
}

void Dog_Walk(struct Dog *a_This){
    printf("Dog walking %s (%s)\n", a_This->Type, a_This->Name);
}

Dog* Dog_Dtor(struct Dog *a_This){
    // Explicit call to parent destructor
    Animal_Dtor((Animal*)a_This);

    printf("dog::dtor\n");

    return a_This;
}

Dog *Dog_Alloc(){
    return (Dog*)malloc(sizeof(Dog));
}

Dog *Dog_New(Dog *a_Dog){
    // Explict call to parent constructor
    Animal_New((Animal*)a_Dog);

    a_Dog->Type = "Dog type";
    a_Dog->vtable.Walk = (Animal_Vtable::Walk_Fun) Dog_Walk;
    a_Dog->vtable.Dtor = (Animal_Vtable::Dtor_Fun) Dog_Dtor;

    return a_Dog;
}

int main(int argc, char **argv){
    /*
      Base class:

        Animal *a_Animal = Animal_New(Animal_Alloc());
    */
    Animal *a_Animal = (Animal*)Dog_New(Dog_Alloc());

    a_Animal->vtable.Walk(a_Animal);

    Animal_Free(a_Animal);
}

PS. 이것은 C++ 컴파일러에서 테스트되고 있습니다만, C 컴파일러에서는 간단하게 동작할 수 있을 것입니다.

C stdio FILE 서브 라이브러리는 통합되지 않은 C에서 추상화, 캡슐화 및 모듈화를 작성하는 방법의 훌륭한 예입니다.

유전과 다형성(OOP에 필수적이라고 생각되는 다른 측면)은 그들이 약속하는 생산성 향상을 반드시 제공하는 것은 아니며, 그들이 실제로 문제 영역에 대한 개발과 사고를 방해할 수 있다는 합리적인 주장이 제기되었습니다.

이데올로기 때문에가장 중요한 것은 프로젝트를 어떻게 분할하느냐이다.프로젝트에서는 .h 파일로 선언된 인터페이스와 .c 파일로 오브젝트 구현을 사용합니다.h하는 모든 만을 vs.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a로 인식한다는 점입니다.void *은 구조 c 파일은 구조 내부를 인식하는 유일한 모듈입니다.

예를 들어 클래스에서는 FOO라고 합니다.

.h 파일

#ifndef FOO_H_
#define FOO_H_

...
 typedef struct FOO_type FOO_type;     /* That's all the rest of the program knows about FOO */

/* Declaration of accessors, functions */
FOO_type *FOO_new(void);
void FOO_free(FOO_type *this);
...
void FOO_dosomething(FOO_type *this, param ...):
char *FOO_getName(FOO_type *this, etc);
#endif

C의 실장 파일은 이와 같습니다.

#include <stdlib.h>
...
#include "FOO.h"

struct FOO_type {
    whatever...
};


FOO_type *FOO_new(void)
{
    FOO_type *this = calloc(1, sizeof (FOO_type));

    ...
    FOO_dosomething(this, );
    return this;
}

그래서 포인터를 그 모듈의 모든 기능에 대해 오브젝트에 명시적으로 부여합니다.C++ 컴파일러는 그것을 암묵적으로 실행하며, C에서는 그것을 명시적으로 씁니다.

는 정말 는는정 i i i i i i i i를 쓴다.this프로그램에서 프로그램이 C++로 컴파일되지 않고 구문 강조 표시 편집기에서 다른 색상으로 컴파일되는 훌륭한 특성이 있는지 확인합니다.

FOO_struct의 필드는 한 모듈에서 변경할 수 있으며 다른 모듈을 다시 컴파일할 필요도 없습니다.

그 스타일이라면 OOP(데이터 캡슐화)의 장점 중 큰 부분을 이미 다루고 있습니다.함수 포인터를 사용하면 상속과 같은 것을 구현하기도 쉽지만, 솔직히 거의 도움이 되지 않습니다.

네, 가능합니다.

이것은 순수 C이며 매크로의 전처리는 없습니다.상속, 다형성, 데이터 캡슐화(개인 데이터 포함)가 있습니다.동등한 보호 수식자가 없습니다. 즉, 상속 체인의 개인 데이터도 개인 데이터임을 의미합니다.

#include "triangle.h"
#include "rectangle.h"
#include "polygon.h"

#include <stdio.h>

int main()
{
    Triangle tr1= CTriangle->new();
    Rectangle rc1= CRectangle->new();

    tr1->width= rc1->width= 3.2;
    tr1->height= rc1->height= 4.1;

    CPolygon->printArea((Polygon)tr1);

    printf("\n");

    CPolygon->printArea((Polygon)rc1);
}

/*output:
6.56
13.12
*/

이것은 읽기에 흥미로웠다.저도 같은 질문에 대해 곰곰이 생각해봤는데, 생각해 보면 다음과 같은 이점이 있습니다.

  • OOP 이외의 언어로 OOP 개념을 구현하는 방법을 상상하면 OOP 언어(나의 경우 C++)의 장점을 이해하는 데 도움이 됩니다.이것에 의해, 어느 타입의 애플리케이션에 C 또는 C++ 중 어느 쪽을 사용할지를 보다 정확하게 판단할 수 있게 됩니다.이러한 애플리케이션에서는, 한쪽의 메리트가 다른 한쪽보다 우선합니다.

  • 이에 대한 정보와 의견을 얻기 위해 웹을 브라우징하던 중 임베디드 프로세서의 코드를 작성하고 있는 C 컴파일러만 있는 작성자를 발견했습니다.http://www.eetimes.com/discussion/other/4024626/Object-Oriented-C-Creating-Foundation-Classes-Part-1

그의 경우, 플레인 C에서 OOP 개념을 분석하고 적응시키는 것이 유효한 작업이었다.C에 OOP 개념을 실장하려고 하면 발생하는 퍼포먼스 오버헤드로 인해 OOP 개념을 희생할 마음이 있었던 것 같습니다.

제가 배운 교훈은 어느 정도 할 수 있다는 것입니다. 그리고 시도해야 할 몇 가지 좋은 이유가 있습니다.

마지막으로, 기계는 스택 포인터 비트를 회전시켜 프로그램 카운터를 점프시키고 메모리 액세스 동작을 계산합니다.효율의 관점에서 보면, 프로그램에 의해서 행해지는 이러한 계산의 수가 적을수록, 좋은 것입니다.하지만 때로는 단순히 이 세금을 내야 합니다. 그래서 우리는 프로그램을 인간의 실수로부터 가장 덜 영향을 받는 방식으로 편성할 수 있습니다.OOP 언어 컴파일러는 두 가지 측면을 모두 최적화하기 위해 노력합니다.프로그래머는 이러한 개념을 C와 같은 언어로 구현하는 데 훨씬 더 신중해야 합니다.

GObject를 확인합니다.이것은 C의 OO와 당신이 원하는 하나의 구현입니다.만약 당신이 정말로 OO를 원한다면, C++나 다른 OOP 언어로 하세요.GObject는 OO언어에 익숙해지면 매우 힘들 때도 있지만, 다른 것들과 마찬가지로 규칙과 흐름에 익숙해질 것입니다.

사람들이 C를 사용해서 C++ 스타일을 모방하려고 하는 것 같아요.객체 지향 프로그래밍 C를 하는 것은 구조 지향 프로그래밍을 하는 것입니다.그러나 지연 바인딩, 캡슐화 및 상속과 같은 작업을 수행할 수 있습니다.상속의 경우 하위 구조에서 기본 구조에 대한 포인터를 명시적으로 정의하며, 이는 명백히 다중 상속의 형식입니다.또, 고객의 요구에 따라,

//private_class.h
struct private_class;
extern struct private_class * new_private_class();
extern int ret_a_value(struct private_class *, int a, int b);
extern void delete_private_class(struct private_class *);
void (*late_bind_function)(struct private_class *p);

//private_class.c
struct inherited_class_1;
struct inherited_class_2;

struct private_class {
  int a;
  int b;
  struct inherited_class_1 *p1;
  struct inherited_class_2 *p2;
};

struct inherited_class_1 * new_inherited_class_1();
struct inherited_class_2 * new_inherited_class_2();

struct private_class * new_private_class() {
  struct private_class *p;
  p = (struct private_class*) malloc(sizeof(struct private_class));
  p->a = 0;
  p->b = 0;
  p->p1 = new_inherited_class_1();
  p->p2 = new_inherited_class_2();
  return p;
}

    int ret_a_value(struct private_class *p, int a, int b) {
      return p->a + p->b + a + b;
    }

    void delete_private_class(struct private_class *p) {
      //release any resources
      //call delete methods for inherited classes
      free(p);
    }
    //main.c
    struct private_class *p;
    p = new_private_class();
    late_bind_function = &implementation_function;
    delete_private_class(p);

편찬하다c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj.

그래서 C++ 스타일을 강요하지 말고 순수한 C 스타일을 고수하라는 조언입니다.또한 이 방법은 API를 매우 깔끔하게 구축하는 데 도움이 됩니다.

1년 동안 이걸 파헤쳐왔어

GObject 시스템은 순수 C에서는 사용하기 어렵기 때문에 C에서는 OO스타일을 쉽게 하기 위해 멋진 매크로를 작성하려고 했습니다.

#include "OOStd.h"

CLASS(Animal) {
    char *name;
    STATIC(Animal);
    vFn talk;
};
static int Animal_load(Animal *THIS,void *name) {
    THIS->name = name;
    return 0;
}
ASM(Animal, Animal_load, NULL, NULL, NULL)

CLASS_EX(Cat,Animal) {
    STATIC_EX(Cat, Animal);
};
static void Meow(Animal *THIS){
    printf("Meow!My name is %s!\n", THIS->name);
}

static int Cat_loadSt(StAnimal *THIS, void *PARAM){
    THIS->talk = (void *)Meow;
    return 0;
}
ASM_EX(Cat,Animal, NULL, NULL, Cat_loadSt, NULL)


CLASS_EX(Dog,Animal){
    STATIC_EX(Dog, Animal);
};

static void Woof(Animal *THIS){
    printf("Woof!My name is %s!\n", THIS->name);
}

static int Dog_loadSt(StAnimal *THIS, void *PARAM) {
    THIS->talk = (void *)Woof;
    return 0;
}
ASM_EX(Dog, Animal, NULL, NULL, Dog_loadSt, NULL)

int main(){
    Animal *animals[4000];
    StAnimal *f;
    int i = 0;
    for (i=0; i<4000; i++)
    {
        if(i%2==0)
            animals[i] = NEW(Dog,"Jack");
        else
            animals[i] = NEW(Cat,"Lily");
    };
    f = ST(animals[0]);
    for(i=0; i<4000; ++i) {
        f->talk(animals[i]);
    }
    for (i=0; i<4000; ++i) {
        DELETE0(animals[i]);
    }
    return 0;
}

여기가 제 프로젝트 사이트입니다(여기서는 doc.를 쓸 시간이 없습니다만, 중국어로 된 doc가 훨씬 좋습니다.

OOC-GCC

그 질문에 대한 답은 '네, 할 수 있어요'입니다.

오브젝트 지향 C(OOC) 키트는 오브젝트 지향으로 프로그래밍을 하고 싶은 사용자를 위한 것으로, 오래된 C에도 고정됩니다.OOC는 클래스, 단일 및 다중 상속, 예외 처리를 구현합니다.

특징들

• C 매크로 및 기능만 사용하고 언어 확장자는 필요 없습니다. (ANSI-C)

• 애플리케이션용으로 읽기 쉬운 소스 코드.일을 가능한 한 간단하게 하기 위해 주의를 기울였다.

• 클래스의 단일 상속

• 인터페이스 및 믹스인에 의한 복수 상속(버전 1.3 이후)

• 예외 구현(순수 C!)

• 클래스의 가상 기능

• 간단한 클래스 구현을 위한 외부 도구

상세한 것에 대하여는, http://ooc-coding.sourceforge.net/ 를 참조해 주세요.

네, 하지만 C로 다형성을 구현하려는 사람은 본 적이 없습니다.

C의 슈퍼셋인 Objective-C를 사용할 것을 제안합니다.

Objective-C는 30년이 지났지만 우아한 코드를 쓸 수 있습니다.

http://en.wikipedia.org/wiki/Objective-C

OOP 접근법이 해결하려는 문제에 대해 우수하다고 확신한다면 왜 OOP 이외의 언어로 해결하려고 합니까?당신은 그 일에 잘못된 도구를 사용하고 있는 것 같아요.C++ 또는 기타 객체 지향 C 배리언트 언어를 사용합니다.

C로 작성된 기존 대형 프로젝트를 코드화하기 위해 질문을 하는 경우, 프로젝트 인프라스트럭처에 사용자(또는 다른 사용자의)의 OOP 패러다임을 강요해서는 안 됩니다.프로젝트에 이미 있는 지침을 따르십시오.일반적으로 깨끗한 API와 격리된 라이브러리 및 모듈은 깨끗한 OOP와 같은 설계를 하는데 큰 도움이 됩니다.

이 모든 것이 끝난 후에도 OOP C를 실행하기로 마음먹은 경우 이 문서(PDF)를 읽어보십시오.

Apple의 Core Foundation API에 대한 문서를 참조하면 도움이 될 수 있습니다.순수한 C API이지만 많은 타입이 Objective-C 오브젝트 등가물에 브리지 됩니다.

Objective-C objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective objective 。와 조금 를 들어 C++는 C++로 정의된다는 것입니다.objc_msg_send오브젝트의 메서드를 호출합니다.컴파일러는 각 괄호 구문을 이러한 함수 호출로 변환하기 때문에 알 필요는 없지만, 당신의 질문을 고려하여 후드 아래에서 동작하는 방법을 배우는 것이 도움이 될 수 있습니다.

오브젝트 지향 C는 가능합니다.한국에서 그런 종류의 코드를 본 적이 있습니다.그것은 제가 몇 년 동안 본 것 중 가장 끔찍한 괴물입니다(이것은 제가 코드를 본 작년(2007)과 같습니다).네, 할 수 있습니다.예, 사람들은 전에도 해왔고 지금도 해내고 있습니다.그러나 C++ 또는 Objective-C는 모두 C에서 탄생한 언어이며 다른 패러다임의 객체 방향을 제공하기 위한 것입니다.

물론 지원 기능이 내장된 언어를 사용하는 것만큼 예쁘지는 않을 것입니다."객체 지향 조립자"라고까지 썼어요.

추가할 OOC 코드:

#include <stdio.h>

struct Node {
    int somevar;
};

void print() {
    printf("Hello from an object-oriented C method!");
};

struct Tree {
    struct Node * NIL;
    void (*FPprint)(void);
    struct Node *root;
    struct Node NIL_t;
} TreeA = {&TreeA.NIL_t,print};

int main()
{
    struct Tree TreeB;
    TreeB = TreeA;
    TreeB.FPprint();
    return 0;
}

다음은 1996년 Jim Larson의 312번 프로그래밍 점심시간 세미나 강연에서 C를 사용한 상속의 예입니다.하이 레벨과 로우 레벨 C

C에서 OOP 개념을 사용하기에 좋은 기사나 책은 무엇입니까?

Dave Hanson의 C Interfaces and Implementations는 캡슐화 및 이름 지정에 탁월하며 함수 포인터 사용에도 매우 적합합니다.데이브는 상속을 시뮬레이션하려고 하지 않는다.

OOP는 프로그램에서 코드보다 데이터를 더 중요하게 여기는 패러다임일 뿐이다.OOP는 언어가 아닙니다.따라서 플레인 C가 단순한 언어인 것처럼 플레인 C의 OOP도 단순합니다.

XT 툴킷 for X Window의 구현에 대해 알아보는 것이 좋습니다.확실히, 치아가 길어지고 있지만, 사용된 많은 구조물은 전통적인 C 내에서 OO 방식으로 작동하도록 설계되었습니다.일반적으로 이는 여러 곳에 간접 레이어를 추가하고 서로 겹치는 구조를 설계하는 것을 의미합니다.

이런 식으로 C에 위치한 OO의 방식대로 정말 많은 것을 할 수 있습니다, 가끔 그런 느낌이 들지만, OO의 개념이 완전히 형성되지 않았습니다.#include<favorite_OO_Guru.h>그들은 정말로 그 당시 확립된 베스트 프랙티스의 많은 부분을 구성했다.OO 언어와 시스템은 오늘날의 프로그래밍 시대정신의 일부만 증류하고 증폭시켰습니다.

C의 OOP에 관한 또 다른 반전에 대해서는, http://slkpg.byethost7.com/instance.html 를 참조해 주세요.네이티브 C만을 사용하여 재진입하기 위한 인스턴스 데이터를 강조합니다.여러 상속은 함수 래퍼를 사용하여 수동으로 수행됩니다.형식 안전이 유지됩니다.다음은 작은 샘플입니다.

typedef struct _peeker
{
    log_t     *log;
    symbols_t *sym;
    scanner_t  scan;            // inherited instance
    peek_t     pk;
    int        trace;

    void    (*push) ( SELF *d, symbol_t *symbol );
    short   (*peek) ( SELF *d, int level );
    short   (*get)  ( SELF *d );
    int     (*get_line_number) ( SELF *d );

} peeker_t, SlkToken;

#define push(self,a)            (*self).push(self, a)
#define peek(self,a)            (*self).peek(self, a)
#define get(self)               (*self).get(self)
#define get_line_number(self)   (*self).get_line_number(self)

INSTANCE_METHOD
int
(get_line_number) ( peeker_t *d )
{
    return  d->scan.line_number;
}

PUBLIC
void
InitializePeeker ( peeker_t  *peeker,
                   int        trace,
                   symbols_t *symbols,
                   log_t     *log,
                   list_t    *list )
{
    InitializeScanner ( &peeker->scan, trace, symbols, log, list );
    peeker->log = log;
    peeker->sym = symbols;
    peeker->pk.current = peeker->pk.buffer;
    peeker->pk.count = 0;
    peeker->trace = trace;

    peeker->get_line_number = get_line_number;
    peeker->push = push;
    peeker->get = get;
    peeker->peek = peek;
}

파티에 조금 늦었지만, 이 주제에 대한 제 경험을 공유하고 싶습니다.저는 요즘 임베디드 컴파일러를 사용하고 있는데, 컴파일러가 C밖에 없기 때문에 C로 작성된 임베디드 프로젝트에 객체 지향적 접근 방식을 적용하고 싶습니다.

지금까지 본 솔루션 대부분은 타입캐스트를 많이 사용하고 있기 때문에 타입의 안전성이 떨어집니다.컴파일러를 잘못 사용해도 도움이 되지 않습니다.이건 절대 용납할 수 없어

요건:

  • 가능한 한 타입캐스트를 피하여 타입의 안전성을 잃지 않도록 합니다.
  • 다형성: 가상 메서드를 사용할 수 있어야 하며 클래스 사용자는 특정 메서드가 가상인지 여부를 인식하지 않아야 합니다.
  • 다중 상속:자주 사용하는 것은 아니지만 여러 개의 인터페이스를 구현(또는 여러 개의 슈퍼클래스를 확장)하는 클래스가 필요할 수 있습니다.

이 기사에서 저의 접근방식을 자세히 설명했습니다.C의 객체 지향 프로그래밍. 또한 기본 클래스 및 파생 클래스에 대한 보일러 플레이트 코드 자동 생성을 위한 유틸리티가 있습니다.

언급URL : https://stackoverflow.com/questions/351733/how-would-one-write-object-oriented-code-in-c

반응형