OOP 및 C의 인터페이스
나는 ANSIC가 객체 지향 프로그래밍 언어가 아니라는 것을 이해합니다.저는 c를 사용하여 특정 oo 기술을 적용하는 방법을 배우고 싶습니다.
예를 들어, 모든 기능 이름이 같지만 해당 기능의 구현이 다른 여러 오디오 효과 클래스를 만들고 싶습니다.
만약 내가 이것을 더 높은 수준의 언어로 만들고 있다면, 나는 먼저 인터페이스를 작성한 다음 그것을 구현할 것입니다.
AudioEffectInterface
-(float) processEffect
DelayClass
-(float) processEffect
{
// do delay code
return result
}
FlangerClass
-(float) processEffect
{
// do flanger code
return result
}
-(void) main
{
effect= new DelayEffect()
effect.process()
effect = new FlangerEffect()
effect.process()
}
C를 사용하여 어떻게 이러한 유연성을 달성할 수 있습니까?
C에서 다형성을 달성할 수 있는 세 가지 방법이 있습니다.
코드 아웃
기본 클래스 함수에서는 다음과 같습니다.switch
클래스 유형 ID에서 특수 버전을 호출합니다.불완전한 코드 예제:typedef enum classType { CLASS_A, CLASS_B } classType; typedef struct base { classType type; } base; typedef struct A { base super; ... } A; typedef struct B { base super; ... } B; void A_construct(A* me) { base_construct(&me->super); super->type = CLASS_A; } int base_foo(base* me) { switch(me->type) { case CLASS_A: return A_foo(me); case CLASS_B: return B_foo(me); default: assert(0), abort(); } }
물론, 이것은 대규모 수업에서는 지루합니다.
개체에 함수 포인터 저장
각 멤버 함수에 대해 함수 포인터를 사용하여 스위치 문을 피할 수 있습니다.다시 말하지만, 이것은 불완전한 코드입니다.typedef struct base { int (*foo)(base* me); } base; //class definitions for A and B as above int A_foo(base* me); void A_construct(A* me) { base_construct(&me->super); me->super.foo = A_foo; }
이제, 호출 코드는 아마도
base* anObject = ...; (*anObject->foo)(anObject);
또는 다음과 같은 방법으로 전처리기 매크로를 사용할 수 있습니다.
#define base_foo(me) (*me->foo)(me)
식을 평가합니다.
me
두 번, 그러니까 이건 정말 나쁜 생각입니다.이것은 수정될 수 있지만, 그것은 이 답변의 범위를 벗어납니다.vvtable 사용
클래스의 모든 개체는 동일한 멤버 함수 집합을 공유하므로 모두 동일한 함수 포인터를 사용할 수 있습니다.이는 C++가 후드 아래에서 수행하는 기능과 매우 유사합니다.typedef struct base_vtable { int (*foo)(base* me); ... } base_vtable; typedef struct base { base_vtable* vtable; ... } base; typedef struct A_vtable { base_vtable super; ... } A_vtable; //within A.c int A_foo(base* super); static A_vtable gVtable = { .foo = A_foo, ... }; void A_construct(A* me) { base_construct(&me->super); me->super.vtable = &gVtable; };
이를 통해 사용자 코드가 디스패치를 수행할 수 있습니다(한 가지 추가 지시사항 포함).
base* anObject = ...; (*anObject->vtable->foo)(anObject);
어떤 방법을 사용해야 하는지는 당면한 작업에 따라 다릅니다.그switch
기반 접근 방식은 두 개 또는 세 개의 소규모 클래스에 대해 쉽게 업데이트할 수 있지만 대규모 클래스 및 계층에는 사용할 수 없습니다.두 번째 접근 방식은 훨씬 더 잘 확장되지만 중복된 함수 포인터로 인해 많은 공간 오버헤드가 발생합니다.vtable 접근 방식은 상당히 많은 추가 구조를 필요로 하며 (코드를 읽기 어렵게 만드는) 훨씬 더 많은 방향을 도입하지만, 이것은 확실히 복잡한 클래스 계층 구조를 위한 방법입니다.
다음과 같이 타협할 수 있습니까?
#include <stdio.h>
struct effect_ops {
float (*processEffect)(void *effect);
/* + other operations.. */
};
struct DelayClass {
unsigned delay;
struct effect_ops *ops;
};
struct FlangerClass {
unsigned period;
struct effect_ops *ops;
};
/* The actual effect functions are here
* Pointers to the actual structure may be needed for effect-specific parameterization, etc.
*/
float flangerEffect(void *flanger)
{
struct FlangerClass *this = flanger;
/* mix signal delayed by this->period with original */
return 0.0f;
}
float delayEffect(void *delay)
{
struct DelayClass *this = delay;
/* delay signal by this->delay */
return 0.0f;
}
/* Instantiate and assign a "default" operation, if you want to */
static struct effect_ops flanger_operations = {
.processEffect = flangerEffect,
};
static struct effect_ops delay_operations = {
.processEffect = delayEffect,
};
int main()
{
struct DelayClass delay = {.delay = 10, .ops = &delay_operations};
struct FlangerClass flanger = {.period = 1, .ops = &flanger_operations};
/* ...then for your signal */
flanger.ops->processEffect(&flanger);
delay.ops->processEffect(&delay);
return 0;
}
함수 포인터의 구조를 사용하여 인터페이스를 구현합니다.그런 다음 인터페이스 구조를 데이터 개체 구조에 포함시키고 인터페이스 포인터를 모든 인터페이스 구성원 함수의 첫 번째 매개 변수로 전달할 수 있습니다.그런 다음 container_of() 매크로를 사용하여 컨테이너 클래스(구현에 따라 다름)에 대한 포인터를 얻습니다.구현을 위해 "container_oflinux kernel"을 검색합니다.그것은 매우 유용한 매크로입니다.
언급URL : https://stackoverflow.com/questions/6304794/oop-and-interfaces-in-c
'programing' 카테고리의 다른 글
data.table에서 이름으로 열을 삭제하려면 어떻게 해야 합니까? (0) | 2023.07.16 |
---|---|
판다 데이터 프레임에서 범주형 데이터 변환 (0) | 2023.07.16 |
NS 레이아웃 제약 조건은 애니메이션으로 제작할 수 있습니까? (0) | 2023.07.16 |
파이썬에서 모든 크기의 빈 목록을 얻으려면 어떻게 해야 합니까? (0) | 2023.07.16 |
텍스트를 어떻게 문장으로 나눌 수 있습니까? (0) | 2023.07.16 |