Programming language evolves always along with Compiler's evolvement.
1. The C++ Object Model:
Stroustrup's original (and still prevailing) C++ Object Model is derived from the simple object model by optimizing for space and access time. Non-static data members are allocated directly within each class object. Static data members are stored outside the individual class object. Static and non-static and virtual and non-virtual function members are also hoisted outside the class object (same as global function in C using name mangling, these functions are shared by all objects by passing ‘this’ parameter to function for manipulating the data encapsulated in object).
Virtual functions are supported in two steps:
- A table of pointers to virtual functions (vtbl) is generated for each class, not each object (this is called the virtual table, shared by all objects of class). That means every class or object has a vtbl if required. In these table, the address of virtual functions (also known as/a.k.a global functions) is stored in its slot.All methos of class wil be converted into a global method with the first parameter 'this' for mem-funcion using name mangling. The non-member function has not 'this' parameter.
- A single pointer to the associated virtual table is inserted or reset within each class object (traditionally, this has been called the vptr which pertains to object when creating or copying or assigning a object only for reference or pointer). The setting, resetting, and not setting of the vptr is handled automatically (by compiler) through code generated within each class constructor, destructor, and copy assignment operator. The type_info object associated with each class in support of runtime type identification (RTTI) is also addressed within the virtual table, usually within the table's first slot. Typeid(a pointer to derived class or base class) = static type of pointer, like typeid( p pointer to Derived ) == typeid( Base*), but typeid (*pointer) == typeid (Derived)
2. Figure illustrates the general C++ Object Model for our Point class. The primary strength of the C++ Object Model is its space and runtime efficiency. Its primary drawback is the need to recompile unmodified code that makes use of an object of a class for which there has been an addition, removal, or modification of the non-static class data members. (The two table model, for example, offers more flexibility by providing an additional level of indirection. But it does this at the cost of space and runtime efficiency. One table for data member, another for function member).
3. The class is its self friend, so in member function the parameter’s protected or private data can be accessed directly if type of parameter is class itself or its base class.
4. Friend function can not have access to static member of class without using object or class.
5. Only when one class has virtual function, the object of class has a virtual table, has type info (RTTI), otherwise all operator related to RTTI is resolved statically.
6. vptr is needed only for reference or pointer.
2. Object Lessons:
1. These are obviously not only very different styles of programming, but also very different ways of thinking about our programs. There are many more or less convincing arguments for why the data encapsulation of an ADT or class hierarchy is better (in the software engineering sense) than the procedural use of global data such as that in C programs.
2. The C++ implementations of a 3D point are more complicated than their C counterpart, particularly the template instances. Example: Template <class type, int dimension> class Point { … };
3. OOP doesn’t mean they are not also considerably more powerful or, again in software engineering sense, better. But being more powerful or better is not necessarily a convincing argument for OOL use.
4. Layout costs for adding encapsulation:
- non-static data member are directly contained within each class object.
- function members are not reflected in the object layout, only one copy of each non-inline member function is generated. Each inline function has either zero or one definition of itself each module in which it is used.
- the primary layout and access0-time within C++ are associated with the virtual, the virtual function mechanism in its support of an efficient run-time binding through a virtual pointer to a virtual function table of class,
- a virtual base class in its support a single, shared instance of a base class occurring multiple times within an inheritance hierarchy.
5. In cfront, for example, the two keywords class and struct are replaced by the shared token AGGR in the parser. The default access is public when using struct, but private when using class.
6. The real issue, however, is not whether all declarations of a user-defined type must use a consistent keyword. Rather the issue is whether the use of the class or struct keyword makes any promise as to the internal declaration of the type. That is, if use of the struct keyword enforces the C concept of a data abstraction, while use of the class keyword enforces the concept of an ADT, then, of course, failure to be consistent is an incorrect usage of the language.
7. The use of a one-element array at the end of a struct to allow individual struct object to address variable-sized arrays:
8. struct Dragon { char pc[1];}
9. struct Dragon *pmumb1 = ( struct Dragon * ) malloc(sizeof(struct Dragon)+strlen(string)+1);
10. The above example may or may not translate well when placed within a class declaration that: specifies multiple access sections containing data, derives from another class or is itself the object of derivation, defines one or more virtual functions, has a virtual base class.
11. The data members within a single access section are guaranteed within C++ to be laid out in the order of their declaration. The layout of data contained in multiple access sections, however, is left undefined.
12. Similarly, the layout of data members of the base and derived classes is left undefined, thereby also negating any guarantee that the trick might work.
13. Composition, rather than inheritance, is the only portable method of combining C and C++ portions of a class (the conversion operator provides a handy extraction method):
14. One reasonable use of the C struct in C++, then, is when you want to pass all or part of a complex class object to a C function. This struct declaration serves to encapsulate that data and guarantees a compatible C storage layout. This guarantee, however, is maintained only under composition. Under inheritance, the compiler decides whether additional data members are inserted within the base struct sub-object.
15. The C++ programming model directly supports three programming paradigms:
- The procedural model as programming in C, and supported within C++;
- The abstract data type model in which users of the abstraction are provided with a set of operations(the public interface), while the implementation remains hidden;
- The object-oriented (OO) model in which a collection of related types are encapsulated through an abstract base class providing a common interface.
16. Although you can manipulate a base class object of an inheritance hierarchy either directly or indirectly, only the indirect manipulation of the object through a pointer or reference supports the polymorphism necessary for OO programming.
17. The actual type of the object addressed is not resolved in principle until runtime at each particular point of execution. In C++, this is achieved only through the manipulation of objects through pointers and references. In contrast, in the ADT paradigm the programmer manipulates an instance of a fixed, singular type that is completely defined at the point of compilation.
18. In C++, polymorphism exists only within individual public class hierarchies.
19. The C++ language supports polymorphism in the following ways:
- through a set of implicit conversions, such as the conversion of a derived class pointer to a pointer of its public base type: BaseClass *p = new DerivedClass();
- Through the virtual function mechanism;
- Through the dynamic_cast and typeid operation.
20. The primary use of polymorphism is to effect type encapsulation through a shared interface usually defined within an abstract base class from which specific subtypes are derived. This not only allows for the addition, revision, or removal of type without requiring changes to user programs. It also frees the provider of a new subtype from having to recode behavior or actions common to all types in the hierarchy itself.
21. The memory requirements to represent a class object in general are the following:
- the accumulated size of its non-static data members;
- plus any padding (between members or on the aggregate boundary itself) due to alignment constraints (or simple efficiency);
- plus an internally generated overhead to support the virtual ( virtual pointer to vtbl).
- The size of empty class is actually 1, not 0 for a comparison ( &a==&b).
22. The memory requirement to represent a pointer, however, is a fixed sized regardless of the type it addresses, or to represent a reference; internally, a reference is generally implemented as a pointer and the object syntax transformed into the indirection required of a pointer.
23. A pointer and a reference support polymorphism because they do not involve any type-dependent commitment of resources. Rather, all that is altered is the interpretation of the size and composition of the memory they address.
24. Any attempt to alter the actual size of the object za, however, violates the contracted resource requirements of its definition.
25. When a base class object is directly initialized or assigned with a derived class object, the derived object is sliced to fit into the available memory resources of the base type. There is nothing of the derived type remaining. Polymorphism is not present, and an observant compiler can resolve an invocation of a virtual function through the object at compile time, thus by-passing the virtual mechanism. This can be a significant performance win if the virtual function is defined as inline. During this process, the vptr will be reset or event there is not vptr for object which is not reference or pointer to class type.
26. To summarize, polymorphism is a powerful design mechanism that allows for the encapsulation of related types behind an abstract public interface, such as our Library_materials hierarchy. The cost is an additional level of indirection, both in terms of memory acquisition and type resolution.
27. C++ supports polymorphism through class pointers and references. This style of programming is called object-oriented.
28. C++ also supports a concrete ADT style of programming now called object-based (OB) non-polymorphic data types, such as String class. It is called final or sealed class in Java or C#.
29. An OB design can be faster and more compact than an equivalent OO design. Faster because all function invocations are resolved at compile time and object construction need not set up the virtual mechanism, and more compact because each class object need not carry the additional overhead traditionally associated with the support of the virtual mechanism. However, an OB design also is less flexible.