2011-02-14 8 views
1

안녕하세요 다음 코드가 있습니다. 구조체 멤버의 void 포인터 및 함수 포인터

typedef struct __vector { 
     int (*container_end) (struct __vector *); 
}vector; 

및 다음 선언과 다른 반복자 구조 :

typedef struct __iterator {  
    void *ptr_to_container; 
    int (*end)(struct __iterator *); 
}iterator;       

int         
end(iterator *itr) {     
    return (itr->ptr_to_container)->container_end(itr->ptr_to_container); 
}  

가이 코드는 ptr_to_container로 컴파일되지 않습니다 무효 포인터입니다.

이 문제의 해결 방법이 있습니까?

container_end 기능은 별도로 정의되며 ptr_to_container은 일부 컨테이너를 가리 킵니다.

감사 Avinash

+0

itr-> ptr_to_container를'__vector *'로 변환 해 보았습니까? –

+1

[식별자로 __vector는 정의되지 않은 동작입니다.] (http://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c) 나는 여러 컴파일러에 대해 알고 있습니다. 실제로 이것에 대해서도 질식 할 것입니다. [참고] (http://c-faq.com/decl/namespace.html) – Flexo

+0

정적 (즉, 컴파일 타임) 다형성을 얻으려고합니다. 이것은 C에서 (코드 생성 단계의 일종) 없이는 본질적으로 불가능합니다. –

답변

2

iterator 구조를 정의 할 때 뭔가 놓친 것 같습니다. 왜 이터레이터는 iterator를 받아들이는 'end'함수에 대한 함수 포인터를 가지고 있습니까? 반복자를 만들려면 다음 함수를 정의 할 수있는 벡터의 정의에서

typedef struct __iterator { 
    void * ptr_to_container; 
    int (*end)(void *); 
} iterator; 

int end(iterator * it) { return it->end(it->ptr_to_container)); } 

(및 기타 데이터 유형) : 당신이 정말 일반적인 싶은 경우

, 당신은 아마도이 대신 정의를 사용할 수 있습니다 :

static int vector_end(vector * v) { /* implementation omittted */ } 

iterator * vector_create_iterator(vector * v) 
{ 
    iterator * it = malloc(sizeof(iterator)); 
    it->ptr_to_container = v; 
    it->end = vector_end; 
    return it; 
} 

그러나 솔루션은 실제로 데이터 구조가 정의되는 방법에 따라 달라집니다. 위의 제안에서, 트래버스하는 방법을 구현하는 것은 각 데이터 구조에 달려 있습니다.

는 대안으로

typedef struct _container container; 

struct _container { 
    int (*end)(container * c); 
}; 

같은 일반적인 데이터 구조 인터페이스를 설정할 수 있습니다 그리고 벡터 구현 것 "전용"이 컨테이너 구조를 입력해야합니다 :

typedef struct _vector { 
    container c; 
    /* other fields required by the vector */ 
} 

static int vector_end(container * c) 
{ 
    vector * v = (vector *) c; 
    ... 
} 

container * create_vector() 
{ 
    vector * v = malloc(sizeof(vector)); 
    v->c.end = vector_end; 
    return v; 
} 

. 반복기는 일반 컨테이너로만 작동 할 수 있습니다.

typedef struct _iterator { 
    container * c; 
    /* other fields used by the iterator, such as current position */ 
} 

int end(iterator * it) { return it->c->end(it->c); } 

샘플을 보면 거의 두 가지 접근법이 뒤섞인 것처럼 보입니다 :-)

+0

그의 방법은 내가 사용하는 방법입니다. ptr_to_container의 defiition을 컨테이너 * – chacham15

+0

@ chacham15로 바꿀 수는 있지만 컨테이너 정의에 두 번째 방법을 사용하지만 첫 번째 방법을 사용하는 경우에는 그렇지 않습니다. – Christoffer

+0

아, 그럼, 어쨌든 이것에 대해 조금 생각 했으므로 이터레이터가 두 번째 접근법에서도 어떻게 사용될 수 있는지 예제를 추가했습니다. – Christoffer

0

당신이 * 벡터에 캐스팅하려고 했습니까?

return ((vector *)(itr->ptr_to_container))->containter_end(itr->ptr_to_container); 

그러나 이것을 수행 하시겠습니까? itr을 사용하여 함수를 호출 한 다음 해당 함수에 itr을 전달합니다. 더 많은 컨텍스트 (코드 추가)가 도움이 될 것입니다.

0

당신은 명시 적으로 벡터 포인터 * ptr_to_container 캐스팅해야합니다

((__vector *)(itr->ptr_to_container))->container_end 

그렇지 않으면 컴파일러가 대상의 구조 무엇인지 알 수 없습니다.

비록 내가 왜 그런 구조를 갖고 싶은지 나는 알 수 없습니다. 상속을 사용하여 여기에 객체 지향을두고 싶지만 명시 적으로 아무 것도 말하지 않고있는 것처럼 보입니다. 그것은 잘 작동하지 않습니다. C에서는 덜 일반적인 구조를 사용하거나 C++로 이동해야합니다.

0

그것은 당신이 당신의 모든 (한 반복자 추상화를 유지해야하는 경우 void * 그것은 벡터 반복자

typedef struct __iterator {  
    vector *ptr_to_container; 
    int (*end)(struct __iterator *); 
}iterator; //probably you'll need to rename to make type of iterator clear 

것을 반복자에

int         
end(iterator *itr) {     
    return ((vector)(itr->ptr_to_container))->container_end(itr->ptr_to_container); 
} 

를 사용하거나 다른 지정해야하는 경우 컨테이너) 아무것도 atm 마음에 온다 ...