既然您在谈论多态性,那么是的,您可以,我们在 C++ 出现之前几年就在做这种事情。
基本上,您使用struct 来保存数据和函数指针列表以指向该数据的相关函数。
因此,在通信类中,您将有一个 open、read、write 和 close 调用,这些调用将作为结构中的四个函数指针以及对象的数据进行维护,例如:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And data goes here.
} tCommClass;
tCommClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;
tCommClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;
当然,上面的那些代码段实际上是在一个“构造函数”中,例如rs232Init()。
当您从该类“继承”时,您只需更改指针以指向您自己的函数。调用这些函数的每个人都会通过函数指针来完成,给你你的多态性:
int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");
有点像手动 vtable。
您甚至可以通过将指针设置为 NULL 来创建虚拟类 - 行为与 C++ 略有不同(运行时的核心转储,而不是编译时的错误)。
这是一段演示它的示例代码。首先是顶层类结构:
#include <stdio.h>
// The top-level class.
typedef struct sCommClass {
int (*open)(struct sCommClass *self, char *fspec);
} tCommClass;
那么我们就有了 TCP 'subclass' 的函数:
// Function for the TCP 'class'.
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
还有 HTTP:
// Function for the HTTP 'class'.
static int httpOpen (tCommClass *http, char *fspec) {
printf ("Opening HTTP: %s\n", fspec);
return 0;
}
static int httpInit (tCommClass *http) {
http->open = &httpOpen;
return 0;
}
最后是一个测试程序来展示它的实际效果:
// Test program.
int main (void) {
int status;
tCommClass commTcp, commHttp;
// Same 'base' class but initialised to different sub-classes.
tcpInit (&commTcp);
httpInit (&commHttp);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHttp.open)(&commHttp, "http://www.microsoft.com");
return 0;
}
这会产生输出:
Opening TCP: bigiron.box.com:5000
Opening HTTP: http://www.microsoft.com
因此您可以看到不同的函数被调用,具体取决于子类。