问题
今天看到《自制编程语言》里面的提到这个不完全类型,我还真不知道
细节
大概是这样的,不让别人知道我们代码内部实现细节
比如我们实现一个栈,我们把数据结构的定义放在头文件里面,然后别人include我们头文件的时候(并添加.o),就能看到具体细节,比如可能就会主动操作里面的num或者array,破坏封装性
#ifndef STACK_H
#define STACK_H
typedef struct Stack{
int num;
int array[MAX_N];
}Stack;
#endif
实现
按照如下实现就不会有这样的问题
//stack.h
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#ifndef STACK_H
#define STACK_H
typedef struct MyStack Stack;
Stack *createStack();
void destroyStack(Stack **s);
int push(Stack **s, int w);
int isEmpty(Stack **s);
int pop(Stack **s);
#endif
//stack.c
#include "stack.h"
#define MAX_N 100
typedef struct MyStack_tag{
int num;
int array[MAX_N];
struct MyStack *node;
}MyStack;
Stack *createStack() {
MyStack *s = (MyStack *)malloc(sizeof(MyStack));
return (Stack *)s;
}
void destroyStack(Stack **s) {
MyStack *stack = (MyStack *)*s;
free(stack);
*s = NULL;
stack = NULL;
}
int push(Stack **s, int w) {
MyStack *stack = (MyStack *)*s;
if(stack->num + 1 <= MAX_N) {
stack->array[stack->num++] = w;
return 1;
}
return 0;
}
int isEmpty(Stack **s) {
MyStack *stack = (MyStack *)*s;
if(0 == stack->num) {
return 1;
}
return 0;
}
int pop(Stack **s) {
MyStack *stack = (MyStack *)*s;
if(0 == stack->num) {
return 0;
}
return stack->array[--stack->num];
}
int getLen(Stack **s) {
MyStack *stack = (MyStack *)*s;
return stack->num;
}
//main.c
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
Stack *s = createStack();
push(&s, 2);
printf("%d\n", pop(&s));
destroyStack(&s);
}
大概逻辑是这样的,我们自己的库:
头文件:typedef struct MyStack Stack
;还有各种对外的接口函数
cpp文件:有详细对自己内部MyStack的定义,可见Mystack
,也可见Stack
,内部实现的用Stack结构体
外部调用:#include
头文件,调用跟Stack相关接口,这里注意,因为main.c
里面,Stack
是延迟定义的,所以不能使用sizeof
等等,也就是说不能直接使用malloc Stack
;而且main.c
对MyStack
不可见,不能使用MyStack
其他语言
面向对象语言中不叫“延迟定义”。而是叫封装、访问权限、接口和多态。类的封装和访问权限可以阻止客户访问类的实现细节,而接口和多态可以隐藏实现细节。
其他说明
Linux C编程一站式学习上面的
C语言的类型分为函数类型、对象类型和不完全类型三大类。对象类型又分为标量和非标量类型。不完全类型是暂时没有完全定义好的类型,编译器不知道这种类型该占几个字节的存储空间。具有不完全类型的变量可以通过多次声明组合成一个完全类型。不完全类型的结构体有重要作用:
struct s{
char data[6];
struct s *next;
};
当编译器处理到第一行struct s{
时,认为struct s{
是一个不完全类型,当处理到第三行struct s *next
;时,认为next
是一个指向不完全类型的指针,当处理到第四行};时struct s
成了一个完全类型,next
也成了一个指向完全类型的指针。但不可再结构体内定义struct s next
,因为它不知道next
将占用几个字节,所以结构体可以递归的定义指针成员但不可以递归的定义变量成员。