了解如何用C编写面向对象的代码对于理解sofsip的代码有很大的好处。主要有如下方法
一,数据隐藏
二,接口抽象
三,继承
Writing Object-Oriented Code
While C does not provide any special object-oriented features on its own, it is possible to program in object-oriented way using C, too. Sofia code make use of many object-oriented features while being written entirely in C.
Data Hiding
Data hiding is a practice that makes separation between two modules very clear. Outside code cannot directly access the data within a module, but it has to use functions provided for that purpose. Data hiding also makes it easier to define a protocol between two objects - all communication happens using function calls.
How to implement data hiding in C? Easiest answer is to only declare data structures in the header files, not to define them. We have a typedef msg_t for struct msg_s in <sofia-sip/msg.h>, but the actual structure is defined in "msg_internal.h". Programs outside msg module does not have access to the struct msg_s , but they have to to access the msg_t object through method functions provided in <sofia-sip/msg.h>. The msg implementation is also free to change the internal layout of the structure, only keeping the function interface unmodified.
Interfaces
Abstract interface is another object-oriented practice used in Sofia. Parser headers, defined in <sofia-sip/msg_types.h>, is a good example of abstract interface. The type for message headers, msg_header_t, is defined using two C structures struct msg_common_s (msg_common_t), and struct msg_hclass_s (msg_hclass_t).
Abstract interface is achieved using virtual function table in msg_hclass_t structure, bit like C++ typically implements abstract classes and virtual functions. For implemenation of each header, the function table is initialized with functions responsible for decoding, encoding and manipulating the header structure. Unlike C++, the class of the object (msg_hclass_t) is represented by a real data structure which also contains header-specific data, like header name.
msg_hclass_t sip_contact_class[] =
{{
/* hc_hash: */ sip_contact_hash,
/* hc_parse: */ sip_contact_d,
/* hc_print: */ sip_contact_e,
/* hc_dxtra: */ sip_contact_dup_xtra,
/* hc_dup_one: */ sip_contact_dup_one,
/* hc_update: */ sip_contact_update,
/* hc_name: */ "Contact",
/* hc_len: */ sizeof("Contact") - 1,
/* hc_short: */ "m",
/* hc_size: */ MSG_ALIGN(sizeof(sip_contact_t), sizeof(void*)),
/* hc_params: */ offsetof(sip_contact_t, m_params),
/* hc_kind: */ msg_kind_append,
/* hc_critical: */ 0
}};
Inheritance and Derived Objects
Inheritance is a object-oriented practice that has limited use in Sofia. Most common example of inheritance is use of su_home_t. Many objects are derived from su_home_t, which means that they can use the various home-based memory management functions from <su_alloc.h
>.
In this sence, inheritance means that a pointer to a derived object can be casted as a pointer to a base object. In other words, the derived object must have the base object at the beginning of its memory area:
struct derived
{
struct base base[1];
int extra;
char *data;
};
There are three alternatives to cast a pointer to derived to a pointer to base:
struct base *base1 = (struct base *)derived;
struct base *base2 = &derived->base;
struct base *base3 = derived->base;
The third alternative works because base was used as a 1-element array.