Process for managing the multiple inheritance of persistent and shared objects6052528Abstract A process for the management of multiple inheritance for application in a system or language employing persistent and shared objects. According to this process, the format of an object is maintained unchanged when it is being loaded from persistent space into virtual space. Moreover, each class producing an object is associated with an identifier of the class constant in all those applications utilizing the class as well as through all the recompilations. The structure of the object is thus independent of the address of storage in memory and of the code of the class producing this object. Finally, according to the present process, an addressing path permitting the management of inheritance is imposed via different tables. Claims I claim: Description FIELD OF THE INVENTION
______________________________________
C1 *v, *v1;
C2 *v2;
C3 *v3;
C4 *v4;
v1 = new C1( ); v2 = new C2( ); v3 = new C3( ); v4 = new C4( );
v = v1; v.fwdarw.m1( ); /* call to m1 defined in C1 */
v = v2; v.fwdarw.m1( ); /* call to m1 defined in C2 */
v = v3; v.fwdarw.m1( ); /* call to m1 defined in C3 */
v = v4; v.fwdarw.m1( ); /* call to m1 defined in C4 */
______________________________________
The problem is thus clearly evident, thanks to this example, among the four possible "v.fwdarw.m1();" calls; there exist three different execution cases, though the compiler is able to interpret this situation as being only a single case. In This case, the C++ language provides a satisfactory solution. Thus, for the resolution of the problems cited above, the C++ language utilizes, on the one hand, pointers which hold the memory address of the object for access to the inherited states and, on the other, indirection tables termed, by the man of art, "virtual tables" for the resolution of the method call. As previously stated, this technique is made explicit by M. A. Ellis and B. Stroustrup in The Annotated C++ Reference Manual, Addison-Wesley, 1990. The example proposed and described with FIG. 1b makes it possible to schematize memory allocation, for the management of inheritance, of a C++ object of class C2 (Obj.sub.-- C2) and that of an object of class C4 (Obj.sub.-- C4), preserving in spirit that each class Ci will define a state Ei and a certain number of methods, certain of them being overloaded (see FIG. 1a). For memory allocation, the compiler then assigned, to each class Ci (C1, C2, C3 and C4), a part Pi (P1, P2, P3 and P4) which is the same for all the objects belonging to this class Ci, either by direct inheritance of an object of class Ci, or by inheritance of an object from a derived class of Ci. All the parts Pi contain three distinct subparts: a first subpart corresponding to a pointer to a virtual table (VT2.1, VT2.2, VT4.1, VT4.2, VT4.3, VT4.4) contained in the code of the class which makes it possible to manage the calling of any method (m1, m2, . . . m7) applicable to an object of class Ci (C2, C4). This field is the same for all the parts; it is called and referenced to the "vtbl" plan. Each element of a virtual table contains two fields, the first being a pointer to a C function storing a C++ method and the second an offset for calculation of the pointer to that part of the object to be passed as the first parameter of the C function, this parameter corresponding to the "this" utilized in the body of a C++ method. Thus, for example, the virtual table VT2.1, pointed to by the "vtbl" field of the part P1 associated with the class C1 of an object of class C2 (Obj.sub.-- C2), contains four elements which each concern a method m1, m2, m3 and m4 stored by class C1, each element containing two fields. The first field m1.sub.-- 2 of the first element is in this case a pointer to the function storing the method m1 in class C2, whereas the second field d1.sub.-- 2 corresponds to the offset permitting calculation of the pointer to the part P2 of the object of class C2. In the same way, the virtual table VT4.3, pointed to by the "vtbl" field of the part P3 associated with the class C3 of an object of class C4 (Obj.sub.-- C4), comprises five elements, each concerning either a method m2, m6 stored by class C3, or an overloaded method m1, m3, m4 inherited from class C1. The first field m1.sub.-- 4 of the first element is in this case a pointer to the function storing the method m1 in class C4, while the second field d3.sub.-- 4 corresponds to the offset permitting calculation of the pointer to the part P4 of the object of class C4. a second part corresponding to pointers to the parts Pj for all the classes Cj from which Ci inherits directly, these pointers being called "Pj.sub.-- addr" and referenced @(Pj). For example, for part P2: "P1.sub.-- addr" (@(P1)) or, for part P4: "P2.sub.-- addr" (@(P2)) and "P3.sub.-- addr" (@(P3)). a third subpart which corresponds to the state Ei defined by the class Ci, this Pi field being named and referenced "st". It is moreover important to remember that a variable of the type Ci, for example, "Ci *V", always points to a part Pi, whatever the real class of the object pointed to. Thus, to define the variable "C2 *V" (FIG. 1b), V designates Obj.sub.-- C2, this variable pointing to the starting address of the object (starting address of part P2), whereas, if V designates Obj.sub.-- C4, the variable V will point to the middle of the object, the starting address of part P2. After having described all the data implemented in C++ objects, and outside them, to manage the semantics of virtual inheritance, an examination shall be made of how these data are utilized to calculate the access to the various parts of the Ei state of an object, or for calling an mi method. It is assumed in the following example that the objects Obj.sub.-- C2 and Obj.sub.-- C4 are designated by means of a pointer of the C2 type contained in a variable V. The cost of accessing the state Ei of an object will vary according to the type of pointer to the object and the part of the state to be accessed. When the part corresponds to the pointer type, the cost of access in this case is merely an indirection. This is the case for access to the state E2 which is translated by "V.fwdarw.st", for object Obj.sub.-- C2 as well as for the object Obj.sub.-- C4. On the other hand, if access is desired to the state E1, that is expressed by "V.fwdarw.P1.sub.-- addr.fwdarw.st", that is to say, this access is at the cost of a double indirection. In fact, there are as many indirections, plus one, as the number of inheritance levels separating the part pointed to from that of the state to be accessed. For example, to gain access from part P4 to the state E1: "P4.fwdarw.P2.sub.-- addr.fwdarw.P1.sub.-- addr.fwdarw.st", or also "P4.fwdarw.P3.sub.-- addr.fwdarw.P1.sub.-- addr.fwdarw.st". As for calling an mi method, the cost is constant whatever the class in which the method called is implemented. Returning to the previous example (Obj.sub.-- C2 and Obj.sub.-- C4, accessed by means of a pointer of type C2 contained in a "V" variable), the code for a "V.fwdarw.m2()" call in C++ is obviously the same as the call made to the object Obj.sub.-- C2 or the object Obj.sub.-- C4. Thus, in this specific example, the call is translated by: "(*(V.fwdarw.vtbl[index(m2)].m)(V+V.fwdarw.vtbl[index(m2)].d, . . . " The first expression (between parentheses) permits the recovery of the address of the pertinent code of the m2 method in the virtual table associated with the object: for the object Obj.sub.-- C2, table VT2.2, m2.sub.-- 1, or for the object Obj.sub.-- C4, virtual table VT4.2, m2.sub.-- 3. The index in the table is calculated statically; it is a priori different for each class in which the method is visible. The second expression permits the calculation of the pointer V designating the part on which the method called always works: pointer to part Pj, here P2, of class Cj, here C2, which defines the method m2 called. This calculation is carried out by recovering the offset relative to the call pointer, this offset being stored in the virtual table, at the address corresponding to the method m2 called: for the object Obj.sub.-- C2 in the virtual table VT2.2, d2.sub.-- 1, or for the object Obj.sub.-- C4 in the virtual table VT4,d2.sub.-- 3. In the context of an object-oriented language compiled by working in main memory, the technique implemented in this method has proven to be reliably effective. On the other hand, this technique leads to numerous problems when there is a desire to apply it to a language manipulating persistent objects, shared by several by several applications in the course of execution. Thus, in this new context which is that for which the invention was implemented, two principal difficulties are encountered, a first which concerns first of all pointers to the virtual tables contained in the code of the classes, this technique posing in effect the following problems relating, on the one hand, to the persistence and, on the other, to the sharing. With regard to the persistence, it is unrealistic to seek a guarantee that the code for a class will always be loaded at the same address, if only because the code for a class must be able to change. The solution to this problem can be achieved by changing the "vtbl" pointers each time an object is loaded in a new session, when the application is executed, but this solution is costly and relatively complex to implement. Furthermore, relative to sharing, it would be necessary to ensure that the code of a class is connected and thus attached to the same address in all the applications which utilize it. The solution in this case would consist of the fixed storage of the code for the classes in a shared library; but this technique cannot be considered seriously because it is poorly adapted to libraries whose code must be precisely able to change regularly, the modification of a shared library simultaneously with the utilization of said library by applications in the course of execution being impossible. Still within this new context, a second difficulty is encountered, this latter, primarily associated with the persistence, concerning the pointers to the parts Pj of the base classes. In fact, it is essential to be able to guarantee that an object will always be coupled to the same virtual address from one session to another. The technique described above can be implemented only with the aid of a UNIX file (trademark owned by UNIX System Laboratories, Inc.) of the type called (by the man of art) "mapped", that is to say, one for which the correspondences are imposed, this being very unlikely where it would be possible to guarantee that this file will always be found at the same virtual address. Another technique could however consist of refreshing these pointers during loading of the object, but this second solution is even more costly and complicated to implement. In conformity with the concept of the present invention, in this context where a system or a language employing persistent and shared objects is utilized, the process for the management of multiple inheritance is remarkable in that the format of an object is maintained unchanged during the loading of said object from persistent space into virtual space, each class producing an object associated with a class identifier constant in all the applications utilizing the class, as through all the recompilations, the structure of the object being thus independent of the address at which it is stored in memory and of the code producing this object, even though an access path permitting the management of inheritance is borrowed via different tables. Thus, according to the solution under claim, a format is proposed for persistent C++ objects, accompanied by an inheritance-management technique making it possible to offer responses to those problems typical of the latter context described above. Its field of application includes all languages employing persistent objects as well as management systems based on object data permitting a multiple inheritance function similar to that of the C++ language (virtual inheritance and virtual methods). There will be no algorithm given here permitting the production of the data structures necessary to the mechanism, nor even the algorithm for the translation of source code into object code utilizing these structures. These algorithms are in fact specific to each of the languages which make use of this technique, even if they have characteristics in common which the man of art will find obvious by referring to the translation example given below, particularly after the description of FIG. 2. An immediate advantage of the proposed object format is that this format is kept identical in the persistent space and in the virtual space, no translation of the format being necessary during the loading of the object from the persistent space, for example, the hard disk, into virtual space, for example, the main memory. Per the invention, the following minimal assumption is made that a class identifier constant for all those objects utilizing the class, as well as through all recompilations, is assigned to each class producing a persistent object. This minimal assumption is indispensable for the implementation of the invention in this context of persistent and shared objects. The class identifier is preferably an integer. Thus, whenever mention is made below of a class Ci, i is the identifier of the class. The same will hold true remarkably for the storage of objects in memory. Each class is associated with a part which is identical for all those objects belonging to this class, each part being composed of two subparts, a first subpart containing an identifier of the real class having produced the object, the identifier being utilized as an index in a table of classes yielding the point of entry for the path permitting the management of inheritance, and a second subpart containing the state defined by the class which produced the object, the totality of attributes defined by this class being regrouped in this state. In this way, for the storage of the objects in memory, the compiler is going to associate with each class a part Pi which is the same for all those objects belonging to this class. In FIG. 2b, part P1, for example, is the same, whether it concerns an object of class C2 (Obj.sub.-- C2) or an object from class C4 (Obj.sub.-- C4). In FIG. 2b, each part Pi is seen to be composed of two subparts rather than three (see FIG. 1b), as in the example above describing the prior art. The first subpart corresponds to the identifier of the real class of the object, that is to say, of the class which produced the object. This identifier is going to be utilized as an index in a table of classes, termed and referred to in the drawing as Tabclass, which yields the entry point of a path permitting the management of inheritance. For a given object, composed of several parts Pi, this identifier is thus duplicated in each part Pi. The identifier for the object Obj.sub.-- C2 is therefore the same for parts P1 and P2; or the identifier for the object Obj.sub.-- C4 is the same for parts P1, P2, P3 and P4. This choice is necessary, because it is desirable to be able to reference the object by any one of its parts, according to the type of variable referencing said object, a variable of type Ci pointing always to a part Pi. This Pi field is called "cid". The second subpart corresponds to the Ei state defined by the class Ci. This field is called "st", as in FIG. 1b. Thus far it can be seen that we have had the benefit of an increase in memory space in an object, since the only thing required is data equivalent to a pointer to the virtual table, data relative to the pointers parts of the direct base classes of a class not being needed. It can now be shown, via the same example presented with the solution of the prior art, how to manage multiple inheritance from tables of indirection, or virtual tables, in a manner original with regard to the management process implemented in the prior art with C++. Assumed, as in the preceding example, is a variable V of type Ci which designates an object Obj.sub.-- Cj of type Cj, Cj being either the class Ci itself, or a derivative class of Ci. The type Ci of the variable determines a group of methods applicable to the object which is, in fact, a subgroup of the group of methods applicable to the object Obj.sub.-- Cj, this latter group being defined by the real type Cj of the object. Remarkably, each base class Cj defines an access mask to methods at the same time applicable to an object of the real Cj type as well as to those parts corresponding to these base classes. That is what is shown in FIG. 2b where the table called Tabclass supplies a pointer to a table of masks called Tabmask.sub.-- Cj for each class Cj, Tabmask.sub.-- C2 and Tabmask.sub.-- C4 in the table containing different masks permitting the manipulation of an object of the Cj type, Obj.sub.-- C2 or Obj.sub.-- C4, to be manipulated. In fact, a mask makes it possible to describe the different types of variables through which the object of a given class can be manipulated. According to the invention, a mask table will contain as many masks as there are inherited classes, plus one, the class having produced the object, each mask (each line of the table) containing three fields. The first field, called "fdeb" corresponds to the offset dd.sub.-- 1 (dd.sub.-- 1 to dd.sub.-- 2 for Tabmask.sub.-- C2 and dd.sub.-- 1 and dd.sub.-- 4 for Tabmask.sub.-- C4), which permits the calculation of a pointer to the part Pi from a pointer to the starting address of the object, and vice versa. The second field, called "tabdep", corresponds to a pointer to an offset table, thus, to the offset table ST2.2 (offset d2.sub.-- 1) for Tabmask.sub.-- C2, or to offset tables ST4.2 (offset d2.sub.-- 1), ST4.3 (offset d3.sub.-- 1) and St4.4 (offsets d4.sub.-- 1, d4.sub.-- 2 and d4.sub.-- 3) for Tabmask.sub.-- C4. In fact, each table contains the possible offset or offsets permitting the manipulation of an object from a variable of a class, from this class to the class or classes from which it inherits. Finally, a third field, called "vtbl", corresponds to a pointer to a virtual table (for Tabmask.sub.-- C2, the virtual tables VT2.1, VT2.2 and, for Tabmask C.sub.-- 4, the virtual tables VT4.1, VT4.2, VT4.3 and VT4.4) whose structure is the same as that for the technique employed with C++, and described with FIG. 1b. The offset corresponding to the "fdeb" field can be useful during the explicit loading or unloading of an object from or to a secondary memory. In fact, during loading, it is the starting address of the object which is generally returned. By the same token, for unloading, it is often necessary to have the pointer at the starting address of the object. Assumed, in order to generalize and study the implementation of inheritance via the structures described with FIG. 2b, is the manipulation of an object from a variable V, defined by "Ci" *V", designating an object of the real type, Cj. Thus, for loading an object, while assuming the existence of an explicit loading instruction expressed by "V=load.sub.-- object (address.sub.-- disk)", where "load.sub.-- object" consists of loading an object from the hard disk into main memory, starting from its disk address and thus returning its virtual address, it is necessary to transform this operation into the following C language expression: (V=load.sub.-- object(address.sub.-- disk), V=V+Tabclass[V.fwdarw.cid][i].fdeb); In the same way, for unloading an object, assuming the existence of an explicit unloading instruction of the form "unload+object(V, address.sub.-- disk, size);" which unloads the object on the disk at the address "address.sub.-- disk" pointed to by the variable V in main memory, or "size" signifies the size of the object, it will be necessary to transform the instruction in the following manner: unload.sub.-- object((V-Tabclass[V.fwdarw.cid][i].fdeb),address.sub.-- disk,size) It will be noted that the size of the object can be easily saved, if necessary, in a supplementary table named, for example, "Size-class", access to the size then being had via "Sizeclass[(V.fwdarw.cid]". At present, regarding access to the Ei state of an object, two cases from the figure can be shown. A first case, when it is the Ei state being accessed and knowing that the variable always points to the part Pi, access is then simply accomplished via "V.fwdarw.st". The cost in this case is thus the same as for the C++ technique described above. The second case presents itself when it is the Ej case being accessed, class Cj being a direct or indirect base class of Ci, access is then accomplished by means of "(V+Tabclass[V.fwdarw.cid][i].tabdep[(index(j)]).fwdarw.st". In this instruction, "index(j)" is an index in the table of Ci base classes, which is determined statically by the code generator, this index being the same for all the masks associated with a given class. The entrance of the offset table (ST2.2, ST4.2, ST4.3 or ST4.4) supplies the offset permitting the calculation of the address of part Pj, starting from the address of part Pi. It is evident that, relative to the first case, the cost is about three indirections and three arithmetic operations: two additions and a multiplication. The cost here is therefore greater than that for the C++ technique, two indirections and three operations. On the other hand, this is cost is constant, whatever the inheritance hierarchy, when it is necessary to add one indirection more for each level traversed with the C++ technique. With regard to calling the mi method, the latter is done in the same manner, the cost being constant with the C++ technique. The mi method is therefore called by: "(*(Tabclass[V.fwdarw.cid][i]vtbl[index(mi)].m))(V.fwdarw.cid][i].vtbl[inde x(mi)].d . . . " Remarkably, the first expression (between parentheses) permits the calculation of the function to be called which corresponds to the method mi, "index(mi)" being defined statically by the code generator which associates, with each class, the virtual table containing the methods applicable to it. The second expression permits the address of the part Pi to be passed as the first parameter of the function by utilizing the offset defined in the virtual table at the index "index(mi)", an output from said virtual table effectively containing, on the one hand, a pointer to the function storing the corresponding method and, on the other, said offset. This virtual table has the same structure for all the masks utilized in the derivative classes. However, the function associated with an entry, as well as the offset, can be different from one mask to another, since the methods can be redefined in the derivative classes. For example, the function m6.sub.-- 4 storing method m6 can be associated either with the offset d3.sub.-- 4 (virtual table VT4.3) or offset d4.sub.-- 4 (virtual table VT4.4). Pursuant to the present, a translation example which will permit the proposed solution to be understood still better. This example is defined in the C++ language, which implements three classes introducing multiple inheritance links.
______________________________________
class Person {
public:
char Name[40];
char FirstName[30];
long BirthDate;
virtual short Age( );
};
class Taxable {
protected:
double TaxableIncome;
public:
virtual void AffectTaxableIncome( );
virtual double calculTax( );
};
class Salary: public virtual Person, public virtual Taxable {
public:
double GrossMonthlySalary;
virtual void AffectTaxableIncome( );
virtual double calculTax( );
};
The translation of this example into C language, implementing the
mechanisms proposed above, is the following:
.General data linked to the example:
typedef int (*T.sub.-- meth)(char *obj);
typedef struct {
T.sub.-- meth m;
long d;
} s.sub.-- vtbl;
typedet struct {
long cid;
long st;
} s.sub.-- Part;
typedef struct {
long fdeb;
long *tabdep;
s.sub.-- vtbl *vtbl;
} s.sub.-- tabmask;
s.sub.-- tabmask *TabClass[ ]=
Tabmask.sub.-- Person,
Tabmask.sub.-- Taxable,
Tabmask.sub.-- Salary
};
long SizeClass[ ]=
{
sizeof(Person),
sizeof(Taxable),
sizeof(Salary)
};
.Data relative to the class Person
#define CID.sub.-- PERSON(long)0)
typedef struct {
long cid;
struct {
char Name[40];
char FirstName[30];
long BirthDate;
} st;
} s.sub.-- PPerson
typedef struct {
s.sub.-- PPerson PPerson;
} Person;
s.sub.-- tabmask Tabmask.sub.-- Person[ ]=
{
{0, NULL, vtbl.sub.-- Person.sub.-- Person}
};
#define INDEX.sub.-- PERSON.sub.-- AGE 0
s.sub.-- vtbl vtbl.sub.-- Person.sub.-- Person[ ]=
{
{(T.sub.-- meth)Person.sub.-- Age, 0}
}.
.Data relative to the Taxable class
#define CID.sub.-- TAXABLE ((long)1)
typedef struct {
long cid;
struct {
double TaxableIncome;
} st;
} s.sub.-- PTaxable;
typedef struct {
s.sub.-- PTaxable PTaxable;
} Taxable;
s.sub.-- tabmask Tabmask.sub.-- Taxable[ ]=
{
{0, NULL, NULL};
{0, NULL., vtbl.sub.-- Taxable.sub.-- Taxable}
};
#define INDEX.sub.-- TAXABLE.sub.-- AFFECTINCOMETAX 0
#define INDEX.sub.-- TAXABLE.sub.-- CALCULTAX 1
s.sub.-- vtbl vtbl.sub.-- Taxable.sub.-- Taxable[ ]=
{
{(T.sub.-- meth)Taxable.sub.-- AffectIncomeTax, 0}
{(T.sub.-- meth)Taxable.sub.-- CalculTax, 0}
};
.Data relative to the Salary class
#define CID.sub.-- SALARY ((long)2)
typedef struct {
long cid;
struct {
double GrossMonthlySalary;
} st;
} s.sub.-- PSalary;
typedef struct {
s.sub.-- Psalary Psalary;
s.sub.-- PPerson PPerson;
s.sub.-- PTaxable PTaxable;
} Salary;
s.sub.-- tabmask Tabmask.sub.-- Salary[ ]=
{
{sizeof(s.sub.-- PSalary), NULL, vtbl Salary Person),
{sizeof(s.sub.-- PSalary) + sizeof(s.sub.-- PPerson), NULL,
vtbl.sub.-- Salary.sub.-- Taxable,
{0, tabdep.sub.-- Salary.sub.-- Salary, vtbl.sub.-- Salary.sub.--
Salary}
};
#define INDEX.sub.-- SALARY.sub.-- AGE ((long) 0)
#define INDEX.sub.-- SALARY.sub.-- AFFECTINCOMETAX ((long) 1)
#define INDEX.sub.-- SALARY.sub.-- CALCULTAX ((long) 2)
s.sub.-- vtbl vtbl.sub.-- Salary.sub.-- Person[ ]=
{
{(T.sub.-- meth)Person.sub.-- Age, 0)
};
s.sub.-- vtbl vtbl.sub.-- Salary.sub.-- Taxable[ ]=
{
{(T.sub.-- meth)Salary.sub.-- AffectIncomeTax,
sizeof (s.sub.-- PPerson)
sizeof (s.sub.-- PSalary)},
{T.sub.-- meth)Salary.sub.-- CalculTax,
sizeof(s.sub.-- PPerson)
sizeof (s.sub.-- PSalary)}
};
s.sub.-- vtbl vtbl.sub.-- Salary.sub.-- Salary[ ]=
{
{(T.sub.-- meth)Person.sub.-- Age, sizeof(s.sub.-- PSalary)}
{(T.sub.-- meth)Salary.sub.-- AffectIncomeTax, 0},
{(T.sub.-- meth)Salary.sub.-- CalculTax, 0}
};
______________________________________
It should be noted that each function is prefixed with the name of the class defining it. In fact, as the methods are translated into the form of C functions and a method can be overloaded in a derivative class, it is necessary to prefix the names of the functions to distinguish two different ones implemented by a single method. Employing the above translation as a point of departure, it is possible to show an example of the utilization of the structures thus defined. It is assumed that the following code fragment is to be translated:
______________________________________
Person
*p;
Salary
*s;
short a;
...
p = s
a = s.fwdarw.Age( ) + p.fwdarw.Age( );
strcpy (s.fwdarw.Name, "toto");
s.fwdarw.GrossMonthlySalary = 10000;
______________________________________
The translation is then the following:
______________________________________
char *p;
char *s;
short a;
...
p = (s + Tabclass[((s.sub.-- Part *)s).fwdarw.cid] [CID.sub.-- SALARY] .
tabdep {CID.sub.-- PERSON]);
a = ({Tabclass[((s.sub.-- Part *).s).fwdarw.cid] [CID.sub.-- SALARY] .
vtbl
[INDEX.sub.-- SALARY.sub.-- AGE).m(s + Tabclass[s.sub.-- Part
*)s).fwdarw.cid]
[CID.sub.-- SALARY] . vtbl [INDEX.sub.-- SALARY.sub.-- AGE).d)) +
Tabclass[((s.sub.-- Part *)s).fwdarw.cid] [CID.sub.-- PERSON] . vtbl
[INDEX.sub.-- PERSON.sub.-- AGE).m(s + Tabclass[(s.sub.-- Part
*)s).fwdarw.cid]
CID.sub.-- PERSON] . vtbl [INDEX.sub.-- PERSON.sub.-- AGE].d)));
strcpy (((s.sub.-- PPerson *) (s + Tabclass[((s.sub.-- Part
*)s).fwdarw.cid] [CID.sub.-- SALARY] . tabdep [CID.sub.-- PERSON])).fwdarw
st.Name, "toto");
((s.sub.-- PSalary *)s) .fwdarw. st.GrossMonthlySalary = 10000;
______________________________________
The solution proposed according to the present invention thus resolves all the problems connected with multiple inheritance in the context of persistent and shared objects, such as, for example, a linkage of objects in a shared UNIX memory segment. It is advantageously applicable to the C++ language when the latter is rendered persistent, but it can likewise be applied to any other language or system of persistent objects supporting the same concepts of inheritance. This solution is easy and effective to implement, the greater part of the treatment being effected statically at the time of compilation. The imposed addressing path can be applied anew, without prior operation, to the object in the process of being loaded. In conformity with the concept of the invention, the structure of the object is, on the one hand, independent of the code of the class and therefore of the address location at which it is going to be stored and, on the other, independent of the code of the class which produced this object.
|
Same subclass Same class Consider this |
||||||||||
