C의 기본 생성자
구조로 정의된 C 사용자 유형에 대해 일종의 기본 생성자(예: C++)를 가질 수 있는 방법이 있습니까?
와 같은 : 에)를pthread_mutex
시 수 하지만 저는 여러분이 선언문에 어떤 구조의 일부(또는 모든) 필드를 채울 수 있는지 알고 싶었습니다.
를 들면 .pthread_mutex
를 들어어,는을 .
pthread_mutex_t my_mutex;
와 같은 효과를 가지다
pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
구조물에 포인터를 가져다 주는 이니셜라이저 함수를 만들 수 있습니다.이것은 일반적인 관례였습니다.
또한 구조물을 생성하고 초기화하는 기능(공장과 같이) - 구조물이 "클라이언트" 코드에서 "초기화되지 않은" 경우는 없습니다.물론이죠. 사람들이 관습을 따르고 "시공자"/공장을 사용한다고 가정할 때...
malloc 또는 free에서 오류 검사가 없는 끔찍한 의사 코드
somestruct* somestruct_factory(/* per haps some initializer agrs? */)
{
malloc some stuff
fill in some stuff
return pointer to malloced stuff
}
void somestruct_destructor(somestruct*)
{
do cleanup stuff and also free pointer
free(somestruct);
}
누군가가 와서 초기 C++ 프리프로세서/컴파일러가 어떻게 이 모든 것을 C에서 수행했는지 설명할 것입니다.
C++는 이 경우 "클래스"가 없다는 점에서 C와 다릅니다.그러나 C(다른 여러 언어와 마찬가지로)는 객체 지향 프로그래밍에 여전히 사용될 수 있습니다.이 경우 생성자는 구조물을 초기화하는 함수가 될 수 있습니다.이는 생성자와 동일합니다(다른 구문만 있음).또 다른 차이점은 malloc()(또는 일부 변형)을 사용하여 개체를 할당해야 한다는 것입니다.C++에서는 'new' 연산자를 간단히 사용할 수 있습니다.
예: C++ 코드:
class A {
public:
A() { a = 0; }
int a;
};
int main()
{
A b;
A *c = new A;
return 0;
}
등가 C 코드:
struct A {
int a;
};
void init_A_types(struct A* t)
{
t->a = 0;
}
int main()
{
struct A b;
struct A *c = malloc(sizeof(struct A));
init_A_types(&b);
init_A_types(c);
return 0;
}
함수 'init_'A_type'은 C++에서 생성자로서 기능합니다.
옛날에 모범 사례로 여겨졌던 완벽한 엔지니어링 솔루션에 대해 이야기해 보겠습니다.
구조의 문제점은 모든 것이 공개되어 있어서 데이터를 숨기지 않는다는 것입니다.
우리는 그것을 고칠 수 있다.
두 개의 헤더 파일을 만듭니다.하나는 코드의 클라이언트가 사용하는 "공개" 헤더 파일입니다.여기에는 다음과 같은 정의가 포함되어 있습니다.
typedef struct t_ProcessStruct *t_ProcessHandle;
extern t_ProcessHandle NewProcess();
extern void DisposeProcess(t_ProcessHandle handle);
typedef struct t_PermissionsStruct *t_PermissionsHandle;
extern t_PermissionsHandle NewPermissions();
extern void DisposePermissions(t_PermissionsHandle handle);
extern void SetProcessPermissions(t_ProcessHandle proc, t_PermissionsHandle perm);
그런 다음 다음과 같은 정의를 포함하는 개인 헤더 파일을 만듭니다.
typedef void (*fDisposeFunction)(void *memoryBlock);
typedef struct {
fDisposeFunction _dispose;
} t_DisposableStruct;
typedef struct {
t_DisposableStruct_disposer; /* must be first */
PID _pid;
/* etc */
} t_ProcessStruct;
typedef struct {
t_DisposableStruct_disposer; /* must be first */
PERM_FLAGS _flags;
/* etc */
} t_PermissionsStruct;
구현 시 다음과 같은 작업을 수행할 수 있습니다.
static void DisposeMallocBlock(void *process) { if (process) free(process); }
static void *NewMallocedDisposer(size_t size)
{
assert(size > sizeof(t_DisposableStruct);
t_DisposableStruct *disp = (t_DisposableStruct *)malloc(size);
if (disp) {
disp->_dispose = DisposeMallocBlock;
}
return disp;
}
static void DisposeUsingDisposer(t_DisposableStruct *ds)
{
assert(ds);
ds->_dispose(ds);
}
t_ProcessHandle NewProcess()
{
t_ProcessHandle proc = (t_ProcessHandle)NewMallocedDisposer(sizeof(t_ProcessStruct));
if (proc) {
proc->PID = NextPID(); /* etc */
}
return proc;
}
void DisposeProcess(t_ProcessHandle proc)
{
DisposeUsingDisposer(&(proc->_disposer));
}
사용자가 공용 헤더 파일에 있는 구조물에 대해 순방향 선언을 하는 경우가 발생합니다.당신의 구조는 불투명해요 고객들이 그걸 가지고 놀 수 없다는 뜻이죠그런 다음 전체 선언에서 일반적으로 호출할 수 있는 모든 구조의 맨 앞에 파괴자를 포함합니다.모든 사람들에게 동일한 처리 기능을 사용할 수 있는 동일한 malloc allocator를 사용할 수 있습니다.노출할 요소에 대해 공개 설정/가져오기 기능을 만듭니다.
갑자기 당신의 코드가 훨씬 더 제정신이 되었습니다.할당자 또는 할당자를 호출하는 함수에서만 구조를 얻을 수 있으므로 초기화를 병목할 수 있습니다.당신은 파괴자들을 만들어 그 물체를 파괴할 수 있게 합니다.그리고 당신도 가보세요.그런데 t_DisposibleStruct보다 더 좋은 이름은 t_vTableStruct일 수도 있습니다. 왜냐하면 그런 이름이기 때문입니다.이제 모든 함수 포인터인 vTableStruct를 사용하여 가상 상속을 구축할 수 있습니다.또한 vtable의 선택 요소를 즉시 변경하는 것과 같이 순수 oo 언어(일반적으로)로 할 수 없는 작업을 할 수도 있습니다.
중요한 점은 구조물을 안전하고 초기화 가능하게 만드는 엔지니어링 패턴이 있다는 것입니다.
아니요, 직접은 아닙니다.가장 가까운 방법은 인스턴스를 할당하고 일부 필드를 채우는 함수를 작성하는 것입니다.
C 구조를 반환하는 함수를 작성할 수 있습니다.
struct file create_file(int i, float f) {
struct file obj = { i, f };
// other code here...
return obj;
}
C에서 "normal" member function을 가질 수 있는지 궁금하다면,어느 정도는 할 수 있습니다.저는 우선 논법적인 목적어 스타일을 선호합니다.첫 번째 인수로 구조체에 포인터를 전달합니다.이렇게 하면 개체에 대한 인터페이스를 정의하는 여러 가지 기능을 사용할 수 있습니다.
int file_get_integer(struct file *self) { return self->i; }
float file_get_float(struct file *self) { return self->f; }
그런 식으로 쓰면 마지막에 있는 것은 추상적인 자료형입니다.C++에서 사용되는 멤버 함수 호출 구문을 에뮬레이트하여 함수 포인터를 구조에 넣은 다음 다음 다음을 수행하는 것을 본 적이 있습니다.
obj.get_integer(&obj);
리눅스 커널에서 파일 시스템 드라이버에 대한 인터페이스를 정의하는 데 사용됩니다.좋아할 수도 있고, 싫어할 수도 있는 글 스타일입니다.저는 그것을 너무 좋아하지 않습니다. 왜냐하면 저는 데이터를 위해 구조의 멤버를 계속 사용하고 있고 인기 있는 객체 지향 언어에서 멤버 함수 호출을 에뮬레이트하는 것을 사용하지 않기 때문입니다.
기본적으로 C++는 메서드의 주소를 포함하는 포인터 목록을 만듭니다.이 목록을 클래스 정의라고 합니다(클래스 정의에 데이터가 더 있지만 지금은 무시합니다).
순수 C에서 "클래스"를 가지는 일반적인 패턴은 "구조 클래스"를 정의하는 것입니다.구조의 필드 중 하나는 클래스의 "인스턴스"를 반환하는 팩토리 함수입니다.매크로를 사용하여 캐스트를 숨길 것을 제안합니다.
typedef struct __class * class;
typedef void (*ctor_ptr)(class);
struct class {
char * name;
ctor_ptr ctor;
... destructor and other stuff ...
}
#define NEW(clz) ((struct something *)(((struct class *)clz)->ctor(clz)))
이제 각 클래스에 대해 "구조 클래스" 유형의 구조를 만들어 클래스를 정의한 다음 해당 클래스에 저장된 생성자를 호출할 수 있습니다.파괴자 등도 마찬가지입니다.
인스턴스에 메서드를 사용하려면 클래스 구조에 메서드를 넣고 인스턴스 구조에 클래스에 대한 포인터를 유지해야 합니다.
#define NEW_SOMETHING() ((struct something *)NEW(&something_definition))
#define METHOD(inst, arg) ((struct something_class *)(((struct something *)inst)->clz)->method(inst, arg))
NEW_SOMETHING
하여 "something"다에 의 새 .something_definition
가 이 Method가 이 인스턴스에서 "method"를 호출합니다.다를 inst
는 사실의 한 예입니다.something
(클래스 포인터 같은 것을 compare합니다.)
상속을 받는 것은 조금 까다롭고 독자들을 위한 연습으로 남겨집니다.
C++에서 할 수 있는 모든 것을 순수 C로 할 수 있습니다. C++ 컴파일러는 마법처럼 CPU를 다른 것으로 대체하지 않습니다.코드가 훨씬 더 필요할 뿐입니다.
예를 보려면 glib(Gtk+ 프로젝트의 일부)를 확인하십시오.
C에서 이 작업을 수행하고 싶다고 가정하면 C++의 구조에 대한 질문이 아닙니다.
보통 하는 일은 init_whatever, 구조(또는 다른 변수)에 포인터를 가져가서 원하는 값으로 설정하는 함수를 만드는 것입니다.
전역 변수(0으로 초기화됨)인 경우 "초기화됨" 플래그를 포함하여 인수가 없는 생성자를 시뮬레이션한 다음 다른 함수에서 해당 플래그를 확인하고 플래그가 0인 경우 구조를 초기화할 수 있습니다.하지만 이것이 좋은 생각인지 전혀 확신할 수 없습니다.
다른 사람이 지적했듯이 매크로로 끔찍한 짓을 할 수도 있습니다
구조물을 생성하고 폐기하는 기능을 사용하는 것에 대해서는 이미 언급한 바 있습니다.그러나 설명에서 "기본 생성자"를 원한다고 언급했습니다. 구조 필드의 일부(모두?)를 기본값으로 초기화하려는 것입니다.
이것은 C에서 함수, 매크로 또는 혼합된 코딩 규칙을 사용하여 수행됩니다.저는 보통 다음과 같은 것을 합니다.
struct some_struct {
int a;
float b;
};
#define some_struct_DEFAULT { 0, 0.0f}
struct some_struct *some_struct_create(void) {
struct some_struct *ptr = malloc(sizeof some_struct);
if(!ptr)
return ptr;
*ptr = some_struct_DEFAULT;
return ptr;
}
// (...)
struct some_struct on_stack = some_struct_DEFAULT;
struct some_struct *on_heap = some_struct_create();
malloc()
,memcpy()
및 C99럴:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define new(TYPE, ...) memdup(&(TYPE){ __VA_ARGS__ }, sizeof(TYPE))
void * memdup(const void * obj, size_t size)
{
void * copy = malloc(size);
return copy ? memcpy(copy, obj, size) : NULL;
}
struct point
{
int x;
int y;
};
int main()
{
int * i = new(int, 1);
struct point * p = new(struct point, 2, 3);
printf("%i %i %i", *i, p->x, p->y);
return 0;
}
아래는 컨스트럭터를 이용한 간단한 프로그램입니다.명시적인 함수 호출 없이 "default_constructor" 함수가 메인 내부에서 호출됩니다.
#include <stdio.h>
void __attribute__ ((constructor)) default_constructor()
{
printf("%s\n", __FUNCTION__);
}
int main()
{
printf("%s\n",__FUNCTION__);
return 0;
}
출력 : default_constructor main
컨스트럭터 함수 내에 몇 가지 초기화 문을 포함하고 디스트럭터 함수를 사용하여 다음과 같이 메모리를 확보할 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
struct somestruct
{
int empid;
char * name;
};
struct somestruct * str1;
void __attribute__ ((constructor)) a_constructor()
{
str1 = (struct somestruct *) malloc (sizeof(struct somestruct));
str1 -> empid = 30228;
str1 -> name = "Nandan";
}
void __attribute__ ((destructor)) a_destructor()
{
free(str1);
}
int main()
{
printf("ID = %d\nName = %s\n", str1 -> empid, str1 -> name);
return 0;
}
이것이 당신에게 도움이 되기를 바랍니다.
사실 그렇지 않아요.내 기억이 맞다면, 수업에 가장 가까운 곳은 구조물입니다.메모리를 할당하고 필드를 채웁니다.일반적인 컨스트럭터 타입을 어떻게 만들 수 있는지 모르겠습니다.이론적으로, 당신은 이것의 일부를 수행할 매크로를 작성할 수 있습니다.하지만 그것이 정말 가치있는 일인지는 확실하지 않습니다.
당신은 C++ 컴파일러를 보는 것이 좋을 것입니다.라이브러리와 매크로를 사용하여 C에 대한 생성자 등을 볼트로 연결하려고 하는 것보다 우아하고 표준적인 방식으로 C와 유사한 구문을 가진 언어에서 기억할 수 있는 것보다 더 많은 객체 지향적인 기능을 제공합니다.
만약 그것이 당신에게 효과가 없다면 GOobject를 보세요.http://en.wikipedia.org/wiki/GObject .GTK와 Gnome에서 사용되는 C의 객체 시스템으로 "C의 객체"를 11로 크랭크합니다.
위키피디아에서:
GLib Object System, 또는 GObject는 휴대용 객체 시스템과 투명한 상호 운용성을 제공하는 자유 소프트웨어 라이브러리(LGPL에서 다루는)입니다.
시스템은 생성자, 파괴자, 단일 상속, 인터페이스, 가상 공개 및 비공개 방식 등을 지원합니다.C++에서 동일한 작업을 수행하는 것보다 훨씬 지루하고 어렵습니다.재미있게 보내!
아니요, 구조물은 데이터 더미에 불과합니다.구조물 내에서 함수를 선언할 수 없으므로 구조물에 대한 생성자를 만들 수 없습니다.
언급URL : https://stackoverflow.com/questions/537244/default-constructor-in-c
'programing' 카테고리의 다른 글
모바일 보기에서 맨 위에 부트스트랩 오른쪽 열 (0) | 2023.10.04 |
---|---|
Changes의 Angular 1.5 구성요소가 작동하지 않음 (0) | 2023.10.04 |
MVC 웹 API, 오류:여러 매개 변수를 바인딩할 수 없습니다. (0) | 2023.10.04 |
jquery UI 테이블과 trwidth로 정렬 가능 (0) | 2023.10.04 |
워드프레스 데이터베이스 $wpdb 대 get_option() (0) | 2023.10.04 |