C ++ Object Model (member)

Source: Internet
Author: User

1 Preface
The previous article mentioned two types of data members of the class: static and nonstatic. There are three types of function members in the class: static, nonstatic, and virtual. I wonder if you have thought about how the class encapsulates data? Why can only access through objects or member functions? Since static data does not belong to a specific object, can it be accessed by the outside world? The function members of the class do not exist in a single object. why can't the outside world access these function members? How are these done? Let's start reading this chapter with these questions.
2. Data Member
Let's take an example:

class Point3d{public://......float x;static list
 
   *freelist;float y;static const int chunksize = 250;float z;};
 

No static data member will be placed in the object layout, but in the data segment of the program. It has nothing to do with individual objects. For the same access section, the order of nonstatic data members in the object is the same as the declared order. C ++ standard requires that "members that appear later have a higher address in the object". That is to say, due to memory Alignment Optimization, members are not necessarily arranged consecutively in the object.
Next let's take a look at the access of data members. Here I will throw a problem first, as shown below:
Point3d origin,*pt;origin.x = 0;pt->x = 0;
What is the difference between accessing x through origin and accessing x through pt? 2.1 The static data member is put forward by the compiler outside the class and is regarded as a global variable visible within the class declaration period. The access to each static Data member and its association with the class do not incur any time or space overhead. Each time a program accesses static members, the compiler will convert it as follows:
// We know that chunksize is a static data member in Point3d origin. x = 250; // access chunksize and Judge pt-> x = 250; // access chunksize and judge

Apparently, the chunksize cannot be accessed from outside. Let's guess why. I wonder if you know the name-mangling technique (the compiler will rename static data member ). Let's take a look at the following code:
class A{static int x;};class B{static int x;};

X in A and B is placed in data segment. Why are there no conflicts between the two variables? The answer seems obvious. The Compiler renames x in A and x in B. The new name is unique and related to the corresponding scope class name. The rename algorithm is name-mangling. Therefore, the chunksize in data segment cannot be accessed at all. The new name is only known to the scope class. Do you feel suddenly enlightened? Let's proceed with the above conversion.
Origin. chunksize = 250; // ==>> converted to Point3d by the compiler: chunksize = 250; pt-> chunksize = 250; // ==>> converted to Point3d by the compiler: chunksize = 250

In this case, there is no difference in accessing chunksize through origin and pt respectively. What changes will happen if chunksize is inherited from the base class or the virtual base class? The answer is whether the static member has only one instance, and its access path is still so direct.
2.2 nonstatic data member
Nonstatic data member is directly stored in every class object. Unless it is called through an explicit or implicit class object, there is no way to directly access them. Or the above example:
class Point3d{public://......float x;float y;float z;};
Point3d origin; // What is the address & origin. x equal?
Cout <"& origin:" <& origin <
 
  
Program running result:
Is the running result clear? The data member in the Access Object adds an offset based on the start address of the object: & Z cursor? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> history/history" brush: java; "> // assume that Point3d has a member function such as Point3d Point3d :: translate (const Point3d & pt) {x + = pt. x; y + = pt. y; z + = pt. z ;}

Function members in the class seem to directly access data members. Is that true? Let's see what the compiler does to this member function. The above functions are converted:
Point3d Point3d::translate(Point3d *const this,const Point3d &pt){this->x += pt.x;this->y += pt.y;this->z += pt.z;}

Yes, the compiler adds a this pointer to the parameter list of each member function to activate the overload. Therefore, nonstatic data member in the class must be called through objects. Then let's go back to the above question.
Point3d * pt3d;
pt3d->x = 0;
// What is the efficiency?
The execution efficiency is exactly the same when x is struct member, class member, single inheritance, and multiple inheritance. However, if x is a virtual base class member, the access speed is slower. Old problems:
Point3d origin, * pt; origin. x = 0; pt-> x = 0; is there a major difference between accessing x through origin and accessing x through pt?

The answer is that when Point3d inherits from a virtual base class, and x is a member of this virtual base class, there will be a difference. At this time, we are not sure about the class type that pt points to (that is, whether it points to a derived class or a base class object ?) The real offset value of the member during compilation is unknown. Therefore, this access must be delayed until the execution period, and can be accessed through additional indirect guidance. However, origin does not have these problems. Because its class type is determined, it is undoubtedly Point3d, And the Offset Value of member in virtual base class has been fixed during compilation. So origin. x can be used without any pressure. Okay, let's talk about data member. If you want to know more about the content, you can refer to the relevant materials. Let's take a look at the member functions.
3. member functions
The above does not show that there are three types of member functions: nonstatic, static, and virtual. Let's discuss them one by one in this order.
3.1 nonstatic member functions
One of the design principles of C ++ is that a member function must have the same execution efficiency as a common non-member function, and the nonstatic member functions in the external class cannot be used. How can this problem be achieved? The principle is very simple. The compiler has secretly converted to a nonmember function instance for the member function instance. For example:
// Assume that Point3d has the following member function Point3d Point3d: magn1 () {// The specific implementation is not our concern} // It is converted by the compiler (name-mangling is not involved here) ==>> Point3d Point3d :: magnitude (Point3d * const this) {// The specific implementation is not our concern} // if member function is const, it is converted to (name-mangling is not involved here) ==>> Point3d Point3d: magnitude (const Point3d * const this) {// The specific implementation is not our concern}

Yes, you are not mistaken. The compiler will add a this pointer to the object in the parameter list of the member function. Adding a parameter to the header or tail of the parameter list is no better than further research. Therefore, member functions cannot be accessed because the parameter list does not match. Then, mangling generates a new function name and becomes a unique external function. Therefore, you cannot access the function even if the parameter list matches, because the function name also changes. Old problems:
Point3d obj,*pt;pt = &obj;obj.magnitude();pt->magnitude();

Do you think there are major differences between the two functions? Next, let's take a look at the mangling algorithm converted by the compiler.
obj.magnitude();//==>>magnitude_7Point3dFv(&obj);pt->magnitude();//==>>magnitude_7Point3dFv(pt);

Obviously, there is almost no difference. Are you familiar with nonstatic member functions? So let's take a look at static member functions.
3.2 static member functions
A major difference between static member functions and nonstatic member functions is that static member functions does not have the this pointer. Therefore, it will inevitably lead to the following results: 1. It cannot directly access nonstatic data members in the class; 2. It cannot be declared as const, volatile, or virtual. 3. It does not need to be called through an object, although we generally call it with an object. A static member function is almost a nonstatic member function that passes through mangling. Let's take a look at mangling's transformation to static member functions:
// Assume that count () is a static member functionunsigned int Point3d in Point3d: count (){//.....} // ==>> unsigned int count_5Point3dSFV (){}

The uppercase letter S in the function name represents static. Let's look at the example below:
&point3d::count()

Let's guess what the value type looks like? Unsigned int (Point3d: *) () or unsigned int (*)()? The answer is obviously the latter. The static member function is now half a nonmember function. Let's take a look.
obj.count();pt->count();

Are there any major differences between the two? Obviously, without the this pointer, count () will be converted into a general nonmember function:
count_7Point3dSFV();

The calls are almost the same.
3.3 virtual member functions
As we all know, there is a virtual table pointer in the object, and the corresponding virtual table has slots of various virtual functions. The water in this place is a bit deep, and I don't want to discuss it so deeply. The reason is: 1. I didn't give it a thorough explanation. 2. Not everyone is interested in such deep things. If you are interested, you can view the relevant information. The difference between a virtual member function and a nonstatic member function is that it is stored in a virtual table. Let's look at the example below:
// If the first virtual function in Point3d is normalize (), then Point3d obj, * pt; pt = & obj; pt-> normalize (); obj. normalize ();

Pt-> normalize (); to know which function call normalize () is, you must know the type of the object indicated by pt. In this process, we need to know two types of objects: 1 pt. 2 virtual function offset. The general practice is to add these two types of information to the virtual table so that you can know the specific call during compilation. However, visual studio 2010 does not seem to do this. The specific practice remains to be studied. The above is a single inheritance, which may be troublesome when multiple inheritance occurs. Under vs2010, a derived class contains n-1 additional virtual tables, and n indicates the number of base classes on the previous layer (there is no additional virtual table for a single inheritance ). Let's look at an example:
class Base1{public:Base1();virtual ~base1();virtual Base1 *clone()const;protected:float data_Base1;};class Base2{public:Bsae2();virtual ~Base2();virtual Base2 *clone()const;protected:float data_Base2;};class Derived:public Base1,public Base2{public:Derived();virtual ~Derived();virtual Derived *clone()const;protected:float data_Derived;};

The memory layout is shown as follows:
Let's take a look at the following group of operations:
Base2 *phase2 = new Derived;

The compiler translates the above Code as follows:
Derived *tmp = new Derived;Base2 *phase2 = tmp? tmp+sizeof(Base1):0;

The address of the new Derived object must be adjusted to point to its Base2 sub-object. Do you understand the reason why the basic class pointer cannot release a subclass object without declaring the Destructor as a virtual function! However, for the sun compiler, the above form is not applicable. In order to adjust the efficiency of the connector during execution, it concatenates multiple virtual tables into one. If you are interested, check related information on your own. We have not discussed the virtual functions under virtual inheritance here. Next we will discuss the above topics:
pt->normalize();obj.normalize();

What is the difference between the two? First, pt-> normalize (); is converted internally to: (* pt-> vptr [0]) (pt. Vptr is the pointer to the virtual table, 0 is the internal offset, and pt is the zhis pointer. Obj. normalize (); is converted internally to: (* obj. vptr [0]) (& obj); is that true? Apparently not. Because it is unnecessary. The above function instance called by obj can only be Point3d: normalize (); after an object calls virtual function, it is always treated as a nonstatic member function by the compiler. So obj. normalize () is internally converted to normalize_7Point3dFV (& obj); so far, it has been roughly completed. Do you see a naked feeling in the class?



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.