什么是C中的编译时封装?

mbl*_*mbl 9 c

当我研究C相对于C ++的优势时,遇到了这一段:

用C进行封装的标准方法是转发声明一个结构,并且仅允许通过函数访问其数据。此方法还会创建编译时封装。编译时封装使我们能够更改数据结构成员,而无需重新编译客户端代码(使用我们接口的其他代码)。另一方面,进行封装C ++的标准方法(使用类)要求在添加或删除私有成员变量时重新编译客户端代码。

我了解如何通过函数声明结构并访问其成员如何隐藏该结构的实现细节。我不明白的是这条线是:

编译时封装使我们能够更改数据结构成员,而无需重新编译客户端代码(使用我们接口的其他代码)。

在什么情况下适用?

Adr*_*ica 4

可能发生这种情况的现实场景是,在硬盘空间非常有限的时代编写的数据库使用单个字节来存储日期的“年份”字段(例如 1973 年 11 月 11 日)73今年将有)。但是,当 2000 年出现时,这将不再足够,年份必须存储为短(16 位)整数。该库的相关(非常简化)标头可能是这样的:

// dbEntry.h
typedef struct _dbEntry dbEntry;

dbEntry* CreateDBE(int day, int month, int year, int otherData);
void DeleteDBE(dbEntry* entry);
int GetYear(dbEntry* entry);

Run Code Online (Sandbox Code Playgroud)

“客户端”程序是:

#include <stdio.h>
#include "dbEntry.h"

int main()
{
    int dataBlob = 42;
    dbEntry* test = CreateDBE(17, 11, 2019, dataBlob);
    //...
    int year = GetYear(test);
    printf("Year = %d\n", year);
    //...
    DeleteDBE(test);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

“原始”实现:

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

struct _dbEntry {
    unsigned char d;
    unsigned char m;
    unsigned char y;    // Fails at Y2K!
    int dummyData;
};

dbEntry* CreateDBE(int day, int month, int year, int otherData)
{
    dbEntry* local = malloc(sizeof(dbEntry));
    local->d = (unsigned char)(day);
    local->m = (unsigned char)(month);
    local->y = (unsigned char)(year % 100);
    local->dummyData = otherData;
    return local;
}

void DeleteDBE(dbEntry* entry)
{
    free(entry);
}

int GetYear(dbEntry* entry)
{
    return (int)(entry->y);
}
Run Code Online (Sandbox Code Playgroud)

然后,在 Y2K 来临之际,该实现文件将更改如下(其他所有内容均保持不变):

struct _dbEntry {
    unsigned char d;
    unsigned char m;
    unsigned short y;   // Can now differentiate 1969 from 2069
    int dummyData;
};

dbEntry* CreateDBE(int day, int month, int year, int otherData)
{
    dbEntry* local = malloc(sizeof(dbEntry));
    local->d = (unsigned char)(day);
    local->m = (unsigned char)(month);
    local->y = (unsigned short)(year);
    local->dummyData = otherData;
    return local;
}
Run Code Online (Sandbox Code Playgroud)

当客户端需要更新以使用新的(千年安全)版本时,不需要更改代码。事实上,您甚至可能不需要重新编译:只需重新链接到更新的对象库(如果是这样的话)足够了。