I'd use a pointer to the method table:

    struct fd_methods_t {
        ssize_t (*read) (int fd, void *buf, size_t nbytes);
        ssize_t (*write) (int fd, const void *buf, size_t n); 
        int (*close) (int fd);
    };

    typedef struct {
        int fd;
        const struct fd_methods_t *methods;
        int __active;
    } fd_t;