Com -- Component Object Model (Component Object Model) is a set of software development methods and specifications proposed by Microsoft. It also represents a software development idea, that is, the idea of component-oriented programming.
COM programming ideology-component-oriented programming ideology (COP)
As we all know, the transition from process-oriented programming to object-oriented programming is realized from C to C ++. The emergence of COM leads to the idea of component-oriented. In fact, the component-oriented idea is an extension and extension of the object-oriented idea. Therefore, let's first recall the object-oriented thinking.
The object-oriented idea is to classify all operations and the objects to be operated (implemented by class ), its goal is to improve code reusability as much as possible (this is one of the biggest advantages of object-oriented compared with process-oriented ). For example, two programs a and B need to operate the class C object, then the code of class C can be reused (that is, both A and B can use the code of class C ). However, for this, object-oriented is not doing well enough. For example, if both program a and program B need to operate Class C objects, programmers of program a and program B must copy the code of class C, then re-compile it. How troublesome it will be! Moreover, if the code of class C is not made public, such reuse is impossible at all (unless the programmers of program a and program B and the programmers of class C are the same person or team, but the limitations are quite large ).
Due to these limitations of object-oriented, many programmers will think that if we need to reuse others' results in programming, we don't need to re-compile others' code. In other words, we want to achieve the goal of directly reusing others' results rather than others' code. This may be very abstract. For example, you will understand it. For example, compile the code of class C to generate a dll. When other programmers want to reuse class C, you just need to load the dll in your own program without re-compiling the class C code (that is why the component must be dynamically linked ). This idea leads to the idea of component-oriented programming.
Next, I will briefly introduce the idea of component-oriented. In the past, applications were always written into a separate module, that is, an application is a separate binary file. Later, after introducing the component-oriented programming idea, a single application file was originally separated into multiple modules for separate writing. Each module has a certain degree of independence, it should also be unrelated to this application. In general, the division of such modules is based on functions. For example, an online office management system must include network communication, database operations, and other functions, we can propose the network communication and database operations separately to form two independent modules. Therefore, a single application is separated into three modules: the master control module, the communication module, and the database module. The communication module and database module can also make it universal, so other applications can use these modules. There are many benefits to doing so. For example, when upgrading the software, you only need to upgrade the modules that need to be modified, then, replace the old module with a new module that is re-generated (but the interface must remain unchanged), while other modules can be completely unchanged. In this way, the software upgrade becomes more convenient and the workload is smaller.
To sum up, the idea of component-oriented programming is module separation. The "separation" here has two meanings: the first is to "divide", that is, to divide applications (especially large software) into multiple modules by function; the second is to "isolate", that is, each module must have a considerable degree of independence and should be "isolated" from other modules as much as possible. These four words are the essence of component-oriented programming ideas and the essence of COM! After understanding these four words, we truly understand the idea of component-oriented programming. (To put it aside, COM is actually a set of norms or standards, but in my opinion, the core of COM lies in its idea, that is, the idea of component-oriented programming. Everyone can set standards, but there is only one idea !)
Advantages of COM
The advantage of COM is the advantage of component-oriented programming. Component-oriented programming has many advantages. The above mentioned software upgrade is only one of them. I have summarized the following advantages:
- Easy to reuse, making software development faster
- Easy software upgrade
- Facilitates division of labor and collaboration in software development
- Allows you to customize your own applications.
The above points do not need to be discussed at the first and second points. The previous sections on the idea of component-oriented programming have fully demonstrated these two advantages. Here I will explain the third and fourth points.
Today, many large software cannot be developed independently by one person, or even by a company. This is because many of today's large software products are too comprehensive and involve a wide range of applications. However, a person's energy is limited. He cannot learn so many aspects of knowledge, nor can he master so many programming technologies. Even if possible, the efficiency of doing so is very low. Therefore, the common situation is division of labor and collaboration. The preceding online office management system is divided into three modules: the main control module, the communication module, and the database module. Because these three modules are quite independent, you can divide all existing developers into three groups, each of which is responsible for one module. And between these three groups, you only need to discuss the interface between each other. In this way, developers do not need to master all programming technologies, or even understand the specific implementation of other modules, but the software can still be effectively developed. This is the so-called division of labor that facilitates software development.
In addition, if a large software wants to allow users to customize their own applications to a certain extent, then COM is also the best choice. For example, A software consists of two modules, module A and Module B. Now, software developers want to provide users with certain flexibility and allow users to customize Module B to implement their own specific applications, you only need to expose all the interfaces of Module B, and you only need to implement all these interfaces when programming module B. Of course, there are still many problems here, such as the registration of COM components, which involves some details of the COM Standard and will not be discussed here.
Several important concept components in COM
The component mentioned here is the so-called "module" that we have discussed repeatedly ". Now I just want to emphasize the conditions that the component must meet. The first is encapsulation. A component must hide its internal implementation details from the external, so that only interfaces can be seen from the external. Then, components must be dynamically linked together without recompiling like the class in the object-oriented method.
Interface
Because the components hide their internal details from the outside, the customer must use a certain mechanism to use the components, that is, to achieve communication between the customer and the components through a certain method, this requires an interface. The so-called interface is the "connection point" exposed by components to provide services to external customers ". External customers cannot see the internal details of the component. All they can see is interfaces. Customers also use interfaces to obtain the services provided by the component. This is a bit like the OSI network protocol layered model. Each layer is like a component, and its internal implementation details are invisible to other layers; each layer provides services to its upper layer through the "Service Access Point", which is like the interface mentioned here. In general, interfaces are always fixed and public. Developers of components must implement these interfaces, while customers obtain services through interfaces. It is this fixed and open interface that allows components and customers to reach an agreement without knowing the other party.
Customer
The customer here refers not to the user who uses the software, but to the program or module that uses a certain component. That is to say, the customer here is relative to the component.
Com implementation principle and Prototype Simulation
An important feature of COM programming is Modularization. Specifically, it is necessary to separate the customer and component, and the customer and component communicate through interfaces. Next, I will introduce how COM separates customers from components, and how it uses interfaces to implement communication between customers and components.
First, let's talk about interfaces. The interface in COM is actually a function address table. After the component implements this interface, the function Address Table fills up the addresses of the interface functions implemented by the component. The customer obtains the interface function pointers in the component through the function address table to obtain the services provided by the component. In a sense, we can understand the interface as a virtual base class in c ++; or, in c ++, we can use a virtual base class to implement the interface! This is because the storage structure of the interface specified in COM is consistent with the structure of the virtual base class in the memory in c ++. Its storage structure is as follows:
Virtual function table
Vtbl pointer ------> Fun1 () pointer -------->
Fun2 () pointer -------->
Fun3 () pointer -------->
............
The Vtbl Pointer Points to a virtual function table, and the table items of this virtual function table are pointers to these virtual functions.
With the interface, how does the component implement the interface? In fact, if you use a virtual base class to implement the interface, the component inherits the virtual base class. As you know, when a class inherits from a virtual base class, it needs to implement the virtual function declared in the virtual base class, which is exactly consistent with the component implementation interface. For example, if there is an interface interfacea, and componentb needs to implement this interface, it can be described in the C ++ language as follows:
// Interface: Class interfacea {virtual void fun1 () = 0; virtual void fun2 () = 0 ;}; // component that implements the interface interfacea: Class componentb: public interfacea {virtual void fun1 () {printf ("fun1 \ n");} virtual void fun2 () {printf ("fun2 \ n ");}}; // The customer only needs to obtain an interfacea pointer pointing to the componentb object to obtain the componentb component service: // the customer who uses the componentb component ://...... Componentb CB; interfacea * Pia = & CB; // obtain the interfacea pointer pointing to the componentb object. The following customers can obtain the component service Pia-> fun1 () through interfaces only (); pia-> fun2 ();//......
However, we noticed that the componentb component is not completely separated from the customer. Because you need to create a componentb entity in the Customer Code, this is unacceptable for customers who only can see interfaces but have no idea about components (for example, the customer does not know the component class name is componentb ). To solve this problem, you can create the component entity in the dynamic link file (such as the DLL file) that implements the component, rather than creating the component entity in the Customer Code. Components are usually in the form of DLL, and a function called createinstance is implemented in the DLL of the implementation component. This function can be called by external customers. It returns an interface pointer. When you call this function, you can obtain the interface pointer pointing to the component object. Its implementation is also simple:
// In the dll that implements component ComponentB: InterfaceA * CreateInstance () {ComponentB CB; InterfaceA * pIA = & CB; return pIA;} // Of Course, the real CreateInstance function is not that simple. The code above is just a simple simulation. After a CreateInstance function is available, the Customer Code becomes: // the customer who uses component ComponentB ://...... InterfaceA * pIA = CreateInstance (); // obtain the InterfaceA pointer pointing to the ComponentB object. The following customers can obtain the component service pIA-> Fun1 () through interfaces only (); pIA-> Fun2 ();//......
In this way, components and customers are completely separated, and only interfaces and functions of CreateInstance are connected.
The above is the basic principle of COM. Of course, as I mentioned earlier, COM is actually a set of standards which define many standards. For example, COM stipulates that each interface must inherit from an interface called IUnknown. I basically didn't mention these standards here, but I just hoped to understand its implementation principle through a simple simulation. The following is a prototype of COM implemented by simulating the COM mechanism, hoping to help you understand COM.
// 1. implements ComponentDll of component ComponentB. dll: // Interface. h // Interface class InterfaceA {public: virtual void Fun1 () = 0; virtual void Fun2 () = 0 ;}; // Component. h // component (implemented interface InterfaceA) class ComponentB: public InterfaceA {public: virtual void Fun1 () {printf ("Fun1 \ n");} virtual void Fun2 () {printf ("Fun2 \ n") ;}}; // ComponentDll. cpp // CreateInstance function ComponentB instance; extern "C" _ declspec (dllexport) InterfaceA * CreateInstan Ce () {InterfaceA * pIA = & instance; return pIA;} // 2、client client.exe: // Client. cpp # include "Interface. h "# pragma comment (lib," ComponentDll ") int main (int argc, char * argv []) {InterfaceA * pIA = 0; pIA = CreateInstance (); if (pIA! = 0) pIA-> Fun1 (); return 0 ;}