What is object-oriented programming?

zhaozj2021-02-16  51

What is "Object-Oriented Programming"? (1991 Revision) What is "Object-Oriented Programming" (1991 Revised Version) Bjarne Stoustrup AT & T Bell LaboratoriesMurray Hill, New Jersey 07974

Zhang Zi translation zhangjun@huawei.com

Translators do not simply see this paper as an introduction to C features. Its significance is that on the one hand, the evolution of the programming style is introduced, as well as the motivation behind this evolution. In another aspect, it specifically clarifies that object-based (OB) and object-oriented (OO) is very meaningful. We can see that whether it is OB or OO, it is just an organizational form of a program. This pointed out what kind of problem with OO focused on solution (how to organize how to organize elasticity, easy to reuse and understand), and do not solve any problem (design, algorithm design), etc.

Abstract "Object-Oriented Programming" and "Data Abstraction" have become commonly used programming terms, however, few people can achieve consistent understanding of their meaning; this article is based on the language as a language such as ADA, C , Module 2, Simula and Smalltalk. This gives an informal definition. Basic ideas are the ability to "support data abstraction" to define and use new data types, and the "support object-oriented programming" is equivalent to the expression ability of class level. At the same time, the generic programming language must be discussed to support such programming styles. Although C is used in the text, the scope of its discussion is not limited to this language.

1 Introduction is not all languages. It is generally believed that APL, ADA, CLU, C , Loops and Smalltalk are object-oriented, I have also heard about discussions on object-oriented design using C, Pascal, Module-2, and Chill. So can I try to use Fortran and COBOL to perform object-oriented design? I think that it must be feasible. In many circles, "object-oriented" has become a "excellent" high-tech synonym, which can see the following three paragraphs in the business publishing area: Ada is an excellent object-oriented is excellent, so Ada is an object-oriented this article from General Programming The perspective of the language states "Object-oriented" is awarded: Section 2 compares the difference between data abstraction and object-oriented, and distinguishes them with other programming styles; at the same time, it is pointed out to support different programming. An important mechanism required for style. Section 3 states the language mechanism required to efficiently support data abstraction. Section 4 discusses the facilities needed to support object-oriented. Section 5 states that traditional hardware architecture and operating systems are limited to data abstraction and object-oriented programming.

The examples of the text use C to write, this part is for the purpose of introducing C , part is because C is a small number of languages ​​that support data abstraction, object-oriented programming and traditional programming style. This article does not discuss concurrency and special hardware support involved in support specific high-level language characteristics.

2. Programming Paradigms Object-Oriented Programming is a programming technology for writing quality codes for a class of issues. A language is called "object-oriented" if it supports (support) object-oriented programming. There is an important difference here. A language is called "Support" programming technology, if it provides means for easy implementation (convenient, securely, and efficient) this style programming; contrary, if additional skills and means need to be used Get a certain style of encoding, this language is not "support" of the programming style, we can only say this language "Enable" has a programming style. For example, people can write structured programs using Fortran, write type security programs in the C language, using data abstraction technology in Module-2, but these tasks have unnecessary difficulties, because these languages ​​are not Support "those programming style. Supports for some programming style not only means the language provides a clear language and can be used directly, but also means a certain check in the compilation time and runtime to prevent the code from unintentional from this style. Type Check is a particularly obvious example, an unisforced inspection and runtime check can also expand the ability of the language to support specific programming styles. At the same time, this support can be enhanced like standard libraries and programming environments. It is not necessarily that if a language has been supported, it must be better than other languages ​​that do not support this feature. There is too much antique here. What is important is not a language that has a language, but it has the characteristics that can be sufficient to support specific programming styles in a particular area. 1. All features must be clear and elegantly integrated into the language. 2. Use these features by combining these features must be sufficient to obtain solutions without having to use other features. 3. The characteristics of counterfeiting and "special purpose" must be as small as possible. 4. All features cannot strong with too much overhead in those programs that do not use them. 5. Users only need to know that language subsets that are configured in the programs can be written.

The last two points can be summarized as "programmers will not be hurt by them." This feature is preferably abandoned if there is any doubt for a feature. Plus a property in the language is much easier than a range of features or from its literature. The following will list some programming styles and their core language mechanisms, but do not intend to discuss it is too in-depth and cumbersome.

2.1 Process programming initial (may also be the most commonly used in current) programming style: decided to need the best algorithm design that can be obtained in those processs is to process the process and execution of algorithms, language provides this parameter delivery Give functions and mechanisms that return values ​​from the function. The literature related to this way of thinking discusses the different ways of passage, distinguishes different parameters, and various processes (processes, functions, macros), and more. Fortran is the earliest process language, Algol60, Algol68, C and Pascal are some subsequent process languages. The square root function is a typical example, which simply generates the square root of the incoming parameter. To this end, the function performs a simple mathematical operation: Double SQRT (Double Arg) {// The code for co 3}

Void some_function () {double root2 = SQRT (2);} From the perspective of the program structure, the functionality has cleared the miscellaneous relationship between the algorithm.

2.2 Data Hide Over time, the focus of programming is focused from the process design to the organization of the data, which reflects the growth of the program size. A set function of data and direct operation data is called a module. The style of programming is: decided to need those module breakdown programs, making data hidden in different modules in this style called "Data Hide Rules". In cases where do not have to bind to data and related to it, you can use only process program design. In particular, those techniques used to design a "good process" can now be applied to each process within the module. The most common example is to define a stack module. There is a problem when designing: 1. Provide a user interface for the stack module (for example, function push () and pop ()) 2. Ensure the stack representation (for example, an element Array) can only access the interface through the module 3. Make sure the stack is performed before it is first accessed, the following is an unhappy stack module external interface: // Declaration of the interface of module stack of charater CHAR POP (); Void Push (char); const stack_size = 100;

Suppose this external definition is stored in the stack.h file, and the inside of its module is as follows: #include "stack.h" static char v [stack_size]; static char * p = v; char pop () {// check for Underflow and pop}

Void Push (Char C) {// Check for overflow and push}

It is very convenient to modify the stack to the chain list, and the user cannot access the internal representation of the stack (because V and P have been declared as static, so you can only reference them within the module that declares their modules). You can use this stack module like this: #include "stack.h" void Some_Function () {char c = pop (push ('c')); if (c! = 'C') error ("impossible");}

Pascal does not provide a satisfactory facility to implement this binding. The only way to isolate one of the other parts of a name and program is to make it within a process, which results in the strange process nested and excessive dependence on the global data. The expression of the C language is slightly better. In the example described above, the data can be saved in the same file in the examples described above to form a module, whereby the programmer can control which name is global visible ( The name being declared for Static is only visible in this module). As a result, C language can support modularization to some extent; however C lacks a general framework for using this mechanism, while the Name Access is too low at STATIC. Pascal's subsequent language, Module-2, more far. It forms the concept of modules, providing some basic languages, such as the material definition module declaration, the explicit control of the name range (Import, Export), the initialization mechanism of the module, and the use of the use of these mechanisms the way. The difference between C and Module-2 can summarize that c is only "enabled" to decompose the program into modules, and Module-2 "support" technology.

2.3 Data Abstraction Modular Programming Development Become a programming style of a type of data set in a type of management module. If someone needs two stacks, he may design a stack management module with the following interface:

class stack_id; // stack_id is a type // no details about stacks or stack_ids are known here stack_id create_stack (int size); // make a stack and return its identifier destroy_stack (stack_id); void push (stack_id, char) char pop (Stack_ID) is of course a major improvement relative to those in the past. However, "Types" implemented in this manner is also distinguished from the language's built-in type. Each type management module must define its own mechanism to generate its own "variable"; there is no clear method here to give variables to identifically, and it is impossible to let the compiler and programming environment understand the name of the variable. At the same time, there is no way to let these variables obey the common variable scope rules and parameters transfer rules. The type established by the module mechanism is different from the built-in type in many important aspects. At the same time, its support is much lower than that of the built-in type. For example: void f () {stack_id s1; stack_id s2; s1 = create_stack (200); // OOPS: Forgot to create S2SHAR C1 = POP (S1, PUSH (S1, 'A')); if (C1! = ' C ') Error ("Impossible"); char C2 = POP (S2, PUSH (S2,' A ')) IF (C2! =' c ') Error ("Impossible");

Destroy (S2); // OOPS, Forgot to Destroy S1}

In other words, the module concept that supports data hidden style is just enabled, but it does not support this style.

The language such as ADA, CLU and C is solved by allowing user definitions and "types" similar to built-in behavior. This "type" is often referred to as "abstract data type". As a result, the programming style becomes: decided to need only data hidden techniques to implement a set of complete operations for each type to implement multiple objects that do not need to generate multiple objects for a type. An arithmetic type such as rational number and plural is a common example of an abstract data type:

Class Complex {Doube Re, IM; PUBLIC: Complex (Double R, Double I) {RE = R; IM = I;} Complex (Double R) {RE = R; IM = 0;} // Float-> Complex Conversion

friend complex operator (complex, complex); friend compelx operator- (complex, complex); // binary minus firend complex opeator- (complex); // unary minus friend compelx operator * (complex, complex); friend complex operator / ( COMPLEX, Complex); // ...}

The declaration of class complex (user-defined type) determines a plural "representation" and a set of operations. "Means" is private, that is, it can only access RE and IM by functions declared in the Complex class. The function can be defined as follows: Complex Operator (Complex A1, Complex A2) {Return Complex (A1.RE A2.RE, A1.IM A2.IM);} can be used like this: Complex A = 2.3; Complex B = 1 / a; complex c = ab * complex (1, 2.3); // ... c = - (A / b) 2; most (but not all) modules can use "type" to get better expression . For those concepts that are more suitable to express "modules", programmers can define a type that generates only a single object as an alternative. Of course, language can also provide a separate module mechanism outside of the custom type mechanism. 2.4 Data Abstraction Problem A Abstract Data Type Defines a class of black boxes, once the definition is completed, then other parts of the program no longer interact. It is difficult to use it for new purposes unless it is modified. Consider defining a type shape for a graphical system. Assume that the current system supports circles, triangles, and squares, and there are other related classes: class point {/*...*/}; class color {/*...*/}; Shape class may be defined as this: ENUM KIND {Circle, Triangle, Squre}; Class Shape {Point Center; Color Color COL; Kind K; // REPRESENTATION OF SHAPE PUBLIC: POINT WHERE () {Return Center;} Void Move (Point To) {center = TO; DRAW (); Void draw (); void rotate (int); // more operation}; in order to allow Draw, Rotate knows what shape is currently processed, where the type of domain "k" must exist (in class Pascal language You can use a variable record with tag K), the function DRAW can be defined as this: void Shape :: Draw () {switch (k) {copy circle: // Draw A Circle; Break; Case Triangle: // DRAW A Triangle; Break; Case Square: // Draw A Square; Break;}} This is confusing. A function like DRAW must understand the current "shapes" currently existing, so each of these functions must be rewritten whenever the system adds a new "shape". In order to define a new "shape", it must be checked and all operations of the Shape may also be modified. Therefore, unless the source code can be modified, it will not be possible to add new "shapes" in the system. Since adding a new "shape" will result in all important operations of Shape, this means that programming requires higher skills, while it is also possible to introduce bugs for existing "shapes". At the same time, the application framework (or part of the general type shape) may require each particular "shape" must have a staggered representation, which will represent a large limit of specific shapes. 2.5 Object-Oriented Programming Problems Differentially distinguishes that there is no general property (with color, painting) and a particularly shape of the proprietary attribute (circle having a radius, using the drawing circle function). This distinction is expressed and utilized to form an object-oriented programming.

Only languages ​​that can be used directly to direct this distinction is to support object-oriented, other languages ​​are not. The SIMULA inheritance mechanism provides a solution. First, specify a class to define the general properties of the shape: Class Shape {Point Center; Color Col; PUBLIC: Point where () {Return Center;} Void Move (Point To) {center = To; Draw ()} Virtual Void Draw (); Virtual Void Rotate (int); // .......} Call interface can be determined, but the function that is not yet determined is marked as "Virtual" (in Simula and C , it can be A subclass is redefined). After these definitions, we can write a general function of the operation: void rotate_all (interface * v, int size, int /) // rotate all memory of vector "v" of size "size" "Angle" degrees {For (int i = 0; i

3.1 Initialization and Clear Once the type of representation is hidden, a mechanism must be provided to perform initialization of the variable. A simple solution is to require a user to initialize it before using a variable. For example: Class Vector {Int Sz; INT * V; PUBLIC: Void Init (INT Size); // Call Init To Initialize Sz and V BEFORE THE FIRST Use of A // Vector // ...} Vector v; // Don't Use v here v .init (10); // Use v here This is easy to cause errors and not elegant enough. A better solution allows type designers to provide a special function for initialization; given this function, allocation, and initializing a variable becomes the same operation. This particular function is often referred to as constructor. In some cases, an object may not be very simple, so it often requires a peer-to-peer operation to perform clearance after the object is last used. In C , such a clear function is called a destructor. Consider a vector type: class vector {int SZ; int * v; public: vector (int); // constructor ~ vector (); // deStructor int & operator []/);}; vector constructor can be defined To allocate space, like this: Vector :: vector (int S) {if ("Bad Vector Size '); SZ = S; V = New Int [S]; // Allocate An Array of "s" integers} vector destructor's destructor :: ~ vector :: ~ vector () {(注: This is best delete v; // deallocate the memory pointed to by v} C Wasp collection is not supported, which allows a type of technique to manage storage space without requiring users to intervene. Storage management is the operation of the construction / destructuring function, but they are often used to perform. thing.

3.2 Assignment and Initialization For many types, controlling its initialization and clearing procedures is already enough, but not all types are true. Sometimes it is also necessary to control the copy process, consider the Vector: Vector V1 [100]; Vector V2 = V1; // make a new vector v2 initialized to v1 v1 = v2; // assign v2 to v1

Here, there must be a mechanism to define V2 initialization and the meaning of V1 assignment, of course, can also choose the providing mechanism to disable this copy. Ideally, these two mechanisms exist. For example: class vector {int * v; int SZ; public: // .... void operator = (vector &); // assignment vector (vector &); // initialization}; give user-defined operations to explain vector Assignment and initialization. Assignment can be defined like this: (Translation: Since Operator = (Vector & A) in the above class vector is declared as a void type, here is the best for Void Vector :: Operator (vector & a)) Vector :: operator = (Vector & A) // Check size and copy elements {if (SZ! = a.sz) Error ("Bad Vector Size for ="); for (int = 0; i

Therefore, VECTOR should define a expression that can be referenced as parameters: Class Vector {// vector of elements of type t * v; int SZ; public: Vector ) {IF (S <= 0) Error ("Bad Vector Size"); V = New T [SZ = S]; // Allocate An Array Of "S" "T" S} T & Opertor [] (INT i) INT size () {return SZ;} // ...} Specific type of vector can be defined and used in this way: Vector v1 (100); // v1 is a vector of 100 integers vector V2 (200); // v2 is a Vector of 200 Complex Numbers V2 [i] = complex (V1 [x], v1 [y]); Ada, CLU and ML support parameterization type. Unfortunately, C does not support (translation, the current C standard supports parameterization type, called template); the marker used here is just to demonstrate; but when necessary, macro analog parameterization types can be used. And those who specify all types of classes do not have more overhead to be introduced at runtime. In general, a parameterized type will always depend on certain aspects of parameter types. For example, some operations of the Vector assume that the parameter type defines assignment operations. So how do people guarantee this? One solution is designer that requires parameterization types to show this dependency. For example, "T must be a type defining assignment operation." Another good way to make the specifications of the parameterized type and the specifications of the parameter types are independent, and the compiler can detect calls that do not exist, and can give corresponding error prompts. For example: Cannot Define Vector :: Operator [] (Non_copy &): Type Non_copy does not has operator = This technique allows us to process dependencies between parameter types and parameterization types at this level. For example, we may define a Vector of a sorting function, the sorting operations may be <, <=, and = operation of the parameter type. However, as long as you do not call the sequencing function of the Vector, we can use a type without and vector and vector

3.4 Abnormal Processing As the program size increases, especially when the library is published, it provides a standard mechanism for processing errors (or more, "abnormal conditions"). The ADA, Algol68, and CLU each support a standard mechanism for processing anomalies. Unfortunately, C does not directly support exception handling (translation, the current C standard has supported exception processing), but must use the function pointer, "exception object", "error status", and C library function Signal and Longjump and other mechanisms to fake . These mechanisms are not normal, and it is also possible to provide a standard framework for processing errors. Recise the example of the vector. What happens when an off-border index value is passed to an Subscribe operation? Vector designer should be able to specify a default behavior for this: class vector {... except vector_range {// define an exception called vector_range // and specify default code for handling it error ("Global, Vector Range Error); EXIT (99);}}}} Vector :: OPEARTOR [] () can trigger an exception handling code instead of calling the error function: int & vector :: Operator [] (int i) {= {(0

3.5 Mandatory has proved that user-defined mandatory is very useful techniques, for example, constructor complex (double) implies a force from Double to Complex. The programmer can clearly indicate forced or when necessary, if there is no second-meaning, the compiler can also in secret introduction: Complex a = complex (1); complex b = 1; // Implicit: 1-> Complex (1 A = B Complex (2); A = B 2 // Implicit: 2-> Complex (2) C Introduction to User-defined Forced Reasons is that the arithmetic expression of the mixed mode in the language that supports arithmetic operations is Very common; at the same time, users who participate in the operation can also be mapped to each other naturally. From the perspective of program organization, there is a type of forcing to prove is exceptionally effective: Complex A = 2; Complex B = A 2; // Interpereted As Operator (a, complex) b = 2 a; // Interpereted As Operator (COMPLEX (2), a) only requires only one function when explaining ' ' operation, and for type systems, the two operands are equally. Further, we see that you can smoothly integrate these two concepts only without any adjustment of the integer concept. This is very different from the "pure object-oriented system", where these operations will be explained below: A 2; //a.opeartor (2) 2 a;: //2.operator (a) This must be modified Class Integer is made to legalize 2.operator (a). When adding new features in a system, modifying existing code must be as avoided, generally, object-oriented programming technology can support this goal well, but here, data abstraction technology provides better s solution.

3.6 Iterators Generally believed that support data abstract languages ​​must provide a means of defining control structures. In particular, a mechanism that is often required to allow the user to access the elements contained in a container type, and cannot force the user to rely on the implementation details of the container type. If there is a powerful mechanism for defining types, it is possible to overload the operator, you can implement this goal without introducing a mechanism for defining the control structure. For vector, users can determine their order by subscript, so it is not necessary to define iterators. However, I still define one to demonstrate this technology. Iteractors can have a lot of style, I prefer to use overload function operators: class vector_iterator {vector & v; int i; public: vector_iterator (vector & r) {i = 0; v = r;} int operator () {RETURN I

3.7 Implementation Problems Support for data abstraction is mostly defined as language features and is implemented by compilers. However, the type of parameterization is best supported by a connector that has more understanding of the semantics of the language; at the same time, exception handling requires support of the environment. They can get good compilation speed and efficiency without sacrificing general and ease of use. With the growth of the defined type, the program starts more dependent from the types from some libraries (not limited to those described in the language). This naturally requires tools to express which parts in the program are inserted into the library, and which parts are extracted from the library; also need tools to find out which parts of the library contain which parts of the library are actually programs Use the like. For compilation languages, it is important to make the code to minimize compilation work after modification. At the same time, the connector / loader can try the ability to load large amounts of independent and unwanted code when loading executing code is also very critical. In particular, if a type is only a few operations being called, the library / connector / loader loads all the operations of this type of operations that are particularly poor. 4. Support for face-oriented objects has two mechanisms to support the basic role in supporting object-oriented programming, the first is the inheritance mechanism of the class; the second is, when compiling the actual type of object, The specific method of the call should be determined based on the actual type of object at runtime. Among them, the design of the method call mechanism is the key. At the same time, the support technique of data abstraction as described above is equally important for supporting objects, as data abstraction, and efforts to support it in the language, it is also effective in object-oriented technology. . The success of these two technologies depends on the design of the type and can use these types efficiently, easily and flexibly. Object-oriented technology is capable of designing a more general, more flexible data type relative to data abstraction.

4.1 Calling mechanism Supports the object-oriented key language feature is a method for calling it for a given object. For example, give a pointer P, how to process calls p-> f (arg)? There is a series of options here. In the language of C and Simula, a language that is widely applied in a static type check can be made by means of a type system to make a selection between different invoking methods. In C , there are two functions called: [1] Normal method call: Specific call that method can be decided in compilation time (by looking for the symbolic table of the compiler), while using the standard process call mechanism A pointer representing an object identity. If the standard process call is not high in certain occasions, the function declares becomes inline, the compiler is trying to exhibit a function in the call location. In this way, people can obtain both similar macros of the expansion mechanism of the macro without sacrificing the semantics of the standard function. Such optimization measures are also valuable for data abstraction. [2] Virtual function call: Function call relies on the actual type of object, in general, the actual type of object can only be determined at runtime. Typically, the pointer P has a type of base class B, and the P-pointed object is a subclass D of B (I wants Shape and Circle in the above example). The call mechanism must check the compiler to determine the function to call the function. Once the function is found, such as D::, you can use the way described above. In the compile time, the name f conversion becomes a index of a function pointer table. Such call mechanisms are almost as effective as ordinary methods, in standard C , only need to make more than 5 memory references. Weak type language needs to be more complex mechanisms. In languages ​​like SmallTalk, you must save the name of all methods of the class to perform a lookup in the runtime: [3] method trigger: First find the correct method name to find the correct method name, then in this table Find whether there is a method "f" if there is, call it; otherwise an error. And static type languages ​​are different in compilation time execution function names, where the method name lookup is performed for an actual object. Compared with the virtual function call, the method is triggered, but it is more flexible. Since the static parameter type check is usually unable to perform, this call mode must be used with dynamic type checks.

4.2 Type Check The "Shape" described above shows the power of the virtual function. So what is the way to trigger? The answer is that we can now try to call any way on any object! The ability to trigger any method on any object allows the designer of the class library to transfer the correct processing data type to the user's head, of course, this simplifies the design of the library. For example: Class Stack {: // Assume Class Any Has A Member Next Any * V; Void Push (any * p) {P-> Next = V; v = P;} Any * Pop () {IF (v == 0) RETURN ERROR_OBJ; ANY * R = V; V = V = V-> Next; Return R;}}; this must have a responsibility to ensure that the following type matching error: stack cs; cs.push New saab900); cs.push (new saab37b); Plane * P = (Plane *) cs.pop (); p-> Takeoff (); p = (plane *) cs.pop (); p-> TACKOFF ); // OOPS! Run Time error: a saab 900 is a car // a car does not have a Takeoff method; the message processing mechanism can detect that the program tries to treat a car as a plane, so I triggered an error. . However, only when the user is a programmer himself, there may be some soothing value; due to lack of static type check, it is difficult to ensure that such errors are not included in the final release program. Naturally, such contradictions in a method-based language will be more prominent in a method-based language. Combining parameterization types and virtual functions can be used in the flexibility, simplicity, and convenience of library design, and the convenience of the library, while do not need to give up static types or introduce overhead in space and time. For example: Stack CS; cs.push (new saab900); // compile time error: car * passed, Plane * Expected Cs.push (new saab37b); plane * p = cs.pop (); P-> Takeoff (); // Fine: a saab 37b is a place. P = cs.pop (); p-> Takeoff;

Some differences between program style and dynamic type check / method triggering based on static type check / virtual function calls. For example, a class specified a determined interface for a class of all the subclasses in SIMULA and C , and the class in SmallTalk specifies an initial interface for the objects of all their subclasses. In other words, the class in SmallTalk is a minimum interface specification, and the user can attempt all other methods that are not specified in the interface; and the C class is a determined interface specification, the user can be confident, only the calls are defined in the interface. The method can be compiled. 4.3 Inheriting a support method to find but do not support inheritance, can this language can be called support for object-oriented? I don't think it is. Obviously, we can use way to find techniques to make objects to accommodate specific application environments, and thus can complete a lot of interesting things. However, in order to avoid confusion, we still need a system to combine the method of the object and the data structure represented as an object. At the same time, in order to make the object's users can understand the behavior of the object, there must be a system's means to represent the commonality between the objects. "This system is standard means" is inherited. Consider a language that supports inheritance but does not support virtual functions or methods, can this language be called an object-oriented? I don't think: The "shape" described above is not a good solution in this language. However, such a language is much stronger relative to a language that only supports data abstraction. This view comes from such observations: many Simula and C -based programs use inheritance to organize their structure, but there is no virtual functions. The ability to express the commonality is a particularly powerful tool, for example, without using our joint, we can solve a variety of "shape" requires a public representation. However, due to the lack of virtual functions, people must express the specific type of objects by means of a "type domain", which leads to the organization's organization lacks module. Class inheritance is a particularly effective programming tool that can not only support object-oriented programming, but also more widely. In object-oriented programming practices, we can use base classes to express general concepts, while using subclasses to express various special cases. This way is only some of the powerful functions of inheritance, however all functions are virtual functions (or all method-looking) languages ​​that emphasize such views. If it is possible to properly control the content inherited from the base class, then the class inherit can be a powerful tool that produces a new type from the existing type. The relationship between subclass and base classes does not always summarize the special case and general, "decomposition" (factoring) can more accurately express the relationship between the subclass and the base class. Inheritance is another reasonable programming tool that we cannot easily predict, and today (even if Simula has been born for more than 20 years), it is easy to say which use methods are misused. 4.4 Multi-inheritance assumption A is the base class of B, then inherits all attributes of A; that is, in addition to some attributes, B is an A. Under such an explanation, it is obvious that B is also useful to inherit the two base clauses A1 and A2. This is called more inheritance. Lift a classic example. Assume that the class library provides two class DISPLAYD and TASK, which are used to represent the display management object and scheduling management object. The programmer can generate a class such as a class: class my_displayed_task: public displayed, public task {// my stuff}; Class my_task: public task {// NOT Displayed // my stuff;}

Class my_displayed: public displayed {// not a task // my stuff;}; If only single inheritance is used, then the programmer can only use two of these three selection. This or will result in repetition of the code, or will result in a lack of elasticity - or often both. In C , such an example can use more inheritance and solve it, and the inheritance is not distinguished significantly, and the static type check is not sacrificed. Embodiments can be solved in compilation time: Class A {public: f (); ...} Class B {public: f (); ...} Class C: Public A, Public, B {...}; Void g () {c * p; p-> f (); // error: Ambiguous} At this point, C is different from the LISP to object-oriented dialects. LISP solves the name conflict by relying on the order of declaration, or regarding the method from different base classes as an equivalent, or combining the same name in the base class into a more complex method in the highest layer class. . In C , we can solve the conflict of the name through an additional function: Class C: Public A, Public B {public: f () {// c's o s stuff a :: f (); b :: f ( } ....} In addition to the concept of independent multiple inheritance, it seems to be more general mechanisms to express classes in a multiple inheritance lattice. Dependencies between. In C , you can use a virtual base class to express a child object in a class object is shared by all other child objects: Class W {...} Class bwindow // window with border: public virtual w {...} Class MWindow: Public Virtual W {...} Class BMW // WINDOW WITH BORDER AND MENU: PUBLIC BWINDOW, PUBLIC MWINDOW {...}; This, in a BMW object, only one W child object is bwindow and mwindow Object sharing. The LISP dialect provides the concept of method combination to reduce the use of such complex class hierarchies in programming, but C is not.

4.5 Package Some members (whether data members or function members) need to be protected to prevent unauthorized access. So how do you reasonably define which functions can access these members? For object-oriented programming languages, the most obvious answer is "all member functions defined on this object." However, it can have a less apparent inference, that is, we can't completely identify a collection, including all functions that have access to these protected members; because you can always be generated from these protected members. New classes, and define new member functions on derived classes. On the one hand, this is a large extent, prevent accidentally accessing protection members (because we will not "unexpected" place to give a new class), on the other hand, it provides elasticity to establish applications using class level ( Because we can derive a new class to give yourself access to the ability of the protection member). Unfortunately, for a data-oriented language, its answer is different: "The function must be listed in the class's statement", but there is no special requirement for these functions itself. In particular, these functions do not have to be a member function of the class. In C , the non-member function of private member is authorized to be called the friend function. The class complex defined above has a friend function. Sometimes, it is also useful to declare a function as many kinds of friends in multiple classes. If you want to understand a type of meaning, especially when you want to modify it, there is a full list of member functions and friend functions. The following example demonstrates several options in C : Class B {// Class Member Are Default Private INT I; Void F1 (); Protected: INT I2; Void F2 (); Public: Int i3; Void F3 Friend void g (b *); // any function can be thinkterated as a friends} The private and protected members cannot be accessed directly by the outside: Void h (b * p) {p-> f1 (); // error: B :: F1 is Private P-> F2 (); // error: b :: f2 is protected p-> f3 (); // fine: b :: f1 is public} Protecting members can access in derived classes, But private members can't: Class D: public b {public: Void g () {f1 (); // erro: B: F1 IS Private F2 (); // Fine: B: F2 IS protected, but d is deived from B f3 (); // Fine: B: F3 is public}} You function can access private and protection members like member functions: Void g (b * p) {p-> f1 (); // Fine: B :: F1 IS Private, Butg () IS A Friend Of B P-> F2 (); // Fine: B :: F2 IS Protected, Butg () IS A Friend Of B P-> F3 (); / / FINE: B :: F1 IS public} With the size of the program, the number of users is growing, and if the user is divided into geographically distributed, the importance of the membership mechanism will increase. Document SNYDER [17] and Stroustrup [18] further discussed the protection problem. 4.6 Implementation Problems To support object-oriented programming, mainly need to improve runtime systems and programming environments. To a certain extent, this is because the language mechanism for object-oriented needs has been introduced by data abstraction, so many additional features are no longer needed.

Object-oriented techniques further blur the boundaries between programming languages ​​and their environments, as a variety of general or specific user-defined types are increasingly filled in the program. This requires further development of runtime systems, library tools, debuggers, performance measuring tools, and monitoring tools. The ideal situation is that these tools are integrated into an environment. SmallTalk is a good example of this. 5 Restrictions To define a language that can make full use of data hidden, data abstraction and object-oriented technology, our main problem is that any common programming must be able to: 1. Run on traditional computers 2. and Traditional operating system coexisting 3. It is comparable to the traditional program language of time efficiency 4. It means that this language must be capable of efficiently perform arithmetic operations (in terms of floating point operations, Fortran); Its access to memory must be available for device drivers; it must be able to generate calls with the quirky standards developed by traditional operating systems. Further, traditional languages ​​must be able to call functions written in object-oriented languages, and object-oriented languages ​​must also be able to call functions written in traditional languages. In addition, if an object-oriented program language relies on technologies that cannot be effectively implemented under traditional system structures, it is impossible to be a universal language. Unless special support is obtained, the general implementation of the method trigger mechanism will become a burden. Similarly, garbage collection may become performance and graft bottlenecks. Most object-oriented languages ​​use garbage collection mechanism to simplify programmers and reduce the complexity of language itself and compilers. However, even if we can use garbage collection in some non-critical areas, once we need, we should be able to retain control of the memory. On the other hand, a program language selects abandon garbage collection, and provides convenient expression means for type management itself, also practical. C is an example. Abnormal handling and concurrency feature are another place in which lurking problems. Any mechanism that relies on the support to support talents can be effectively implemented. Another way to own the "low" feature in a language is to use a separate "low" language in the main application field.

6. Conclusion Based on inheritance is called an object-oriented programming method, based on user-defined types of programming is based on data abstract programming methods. In addition to rare some exceptions, object-oriented programming can be considered a supercoming of data abstraction. Only the correct support these technologies can be effective; support for data abstraction mainly comes from the language itself, and object-oriented needs further support from the programming environment. For versatility, support data abstraction and object-oriented languages ​​must be able to efficiently utilize hardware.

7. Aiming on this earlier version of this earlier version of the Association of Simula Uses meeting in Stockholm. The discussion there has led to a lot of improvements to this style and content. Brain Kernighan and Ravi Sethi have given a lot of constructive comments. At the same time, I would like to thank all people who have contributed to enhanced C .

8. References, please refer to the original text

转载请注明原文地址:https://www.9cbs.com/read-26246.html

New Post(0)