tag:blogger.com,1999:blog-27629768891163035902024-03-08T05:29:36.027-08:00Implementation DetailsA blog about the way features of high-level programming languages are implemented at a lower level.Imagisthttp://www.blogger.com/profile/06175695035725315419noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-2762976889116303590.post-76574711576401300772009-11-04T06:55:00.000-08:002009-11-04T07:34:55.498-08:00Objects, Part 2: Inheritance and Name ManglingAs was covered in <a href="http://implementation-details.blogspot.com/2009/11/objects-part-1-members-methods-and.html">the previous post</a>, we are dealing with how C++ classes would compile down to equivalent C code. Consider the following classes:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C++<br />class Parent<br />{<br /> public:<br /> int getParentMember();<br /> void setParentMember(int);<br /> protected:<br /> int parent_member;<br />};<br /><br />class Child: public Parent<br />{<br /> public:<br /> int getChildMember();<br /> void setChildMember(int);<br /> private:<br /> int childMember;<br />};<br /><br />int Parent::getParentMember()<br />{<br /> return this->parentMember;<br />}<br /><br />void Parent::setParentMember(int p)<br />{<br /> this->parentMember = p;<br />}<br /><br />int Child::getChildMember()<br />{<br /> return this->childMember;<br />}<br /><br />void Child::setChildMember(int c)<br />{<br /> this->childMember = c;<br />}<br /></code></pre><br />The <tt>Parent</tt> class' C equivalent is straightforward. <tt>Parent</tt> is really no different from any of the classes we've dealt with so far:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C<br />struct Parent<br />{<br /> int (*getParentMember)();<br /> void (*setParentMember)(int);<br /> int parentMember;<br />};<br /><br />// Parent::Parent()<br />void constructor(struct Parent* this)<br />{<br /> this->getParentMember = getParentMember;<br /> this->setParentMember = setParentMember;<br />}<br /><br />// Parent::~Parent()<br />void destructor(struct Parent* this)<br />{<br />}<br /><br />// int Parent::getParentMember()<br />int getParentMember(struct Parent* this)<br />{<br /> return this->parentMember;<br />}<br /><br />void setParentMember(struct Parent* this, int p)<br />{<br /> this->parentMember = p;<br />}<br /></code></pre>Imagisthttp://www.blogger.com/profile/06175695035725315419noreply@blogger.com0tag:blogger.com,1999:blog-2762976889116303590.post-30174432668783170032009-11-03T14:28:00.000-08:002009-11-04T07:37:18.603-08:00Objects, Part 1: Members, Methods, and Constructors/DestructorsMany programmers today take object-oriented programming for granted. In fact, at my university, I never once wrote a program in a programming language that didn't support objects (okay, MIPS Assembly, but does that <em>really</em> count as a programming language?). However, there once was a time when objects didn't exist, and people still did most of the same things that people do with object orientation today. In fact, early C++ compilers, which included object orientation, compiled to C. So how did they do it?<br /><br />The most basic part of an object is its members. Let's take a look.<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C++<br />class Object<br />{<br /> int member;<br />};<br /><br />// C<br />struct Object<br />{<br /> int member;<br />};<br /></code></pre><br />Well, that was pretty straightforward. Boring, even. But wait, what about public and private?<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C++<br />class Object<br />{<br /> public:<br /> int publicMember;<br /> private:<br /> int privateMember;<br />};<br /><br />// C<br />struct Object<br />{<br /> int publicMember, privateMember;<br />};<br /></code></pre><br />You may be thinking, "This fellow is an idiot, can't he see that he has treated <tt>public_member</tt> and <tt>private_member</tt> as if they were exactly the same?" The answer is, "Yes." They <em>are</em> treated exactly the same, at least in C++. <em>Public and private are only enforced by the compiler at compile time.</em> As soon as compilation is done, private members are just the same as public variables. This is why public and private aren't to be used for security. The distinction is only there to keep the programmer from making mistakes. Other access keywords such as <tt>protected</tt> and <tt>friend</tt> are also completely irrelevant after compilation.<br /><br />I will add that some languages such as Java do enforce a distinction between access levels at runtime. However, this is still only for preventing programmer mistakes, and not for security. In fact, one can even bypass the restrictions with reflection.<br /><br />Next we look at methods. Consider the following class:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C++<br />class Object<br />{<br /> public:<br /> int getMember();<br /> void setMember(int);<br /> private:<br /> int member;<br />};<br /><br />int Object::getMember()<br />{<br /> return this->member;<br />}<br /><br />void Object::setMember(int m)<br />{<br /> this->member = m;<br />}<br /></code></pre><br />We can easily change it to a struct and change the methods to function pointers...<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C<br />struct Object<br />{<br /> int (*getMember)();<br /> void (*setMember)(int);<br /> int member;<br />};<br /><br />int getMember()<br />{<br /> return this->member;<br />}<br /><br />void setMember(int m)<br />{<br /> this->member = m;<br />}<br /></code></pre><br />...but there is a serious issue with this C code. <tt>this</tt> isn't a keyword in C and it's never declared either in the global scope or in the function. We can get a clue about this from Python:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code># Python<br /># I know "self" is the idiomatic name in Python,<br /># but it's legal to name it whatever you want<br /># and it makes my example clearer.<br />class Object:<br /> def getMember(this):<br /> return this.foo<br /> def setMember(this,f):<br /> this.foo = f<br /></code></pre><br />Python is the only object oriented language I know of which requires the programmer to explicitly declare the <tt>this</tt> (or <tt>self</tt>) argument to a method. However, under the covers, <em>all</em> object oriented languages work this way. They just abstract it away from the user as a form of syntactic sugar. This allows us to complete our C code:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C<br />struct Object<br />{<br /> int (*getMember)();<br /> void (*setMember)(int);<br /> int member;<br />};<br /><br />int getMember(struct Object* this)<br />{<br /> return this->member;<br />}<br /><br />void setMember(struct Object* this, int m)<br />{<br /> this->member = m;<br />}<br /></code></pre><br />There are just a few more pieces of the puzzle which we need to make our class usable; a default constructor and destructor:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C<br />void constructor(struct Object* this)<br />{<br /> this->getMember = getMember;<br /> this->setMember = setMember;<br />}<br /><br />void destructor(struct Object* this)<br />{<br />}<br /></code></pre><br />Note that so far, our destructor doesn't do anything.<br /><br />Now we can translate some basic usages of our class:<br /><pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>// C++<br />{<br /> Object stackAllocated;<br /> Object* heapAllocated = new Object();<br /><br /> stackAllocated.setMember(0);<br /> stackAllocated.getMember();<br /><br /> heapAllocated->setMember(1);<br /> heapAllocated->getMember();<br /><br /> delete heapAllocated;<br />}<br /><br />// C<br />{<br /> struct Object stackAllocated;<br /> constructor(&stackAllocated);<br /> struct Object* heapAllocated;<br /> heapAllocated = malloc(sizeof(struct Object));<br /> constructor(heapAllocated);<br /><br /> setMember(&stackAllocated,0);<br /> getMember(&stackAllocated);<br /><br /> setMember(heapAllocated,1);<br /> getMember(heapAllocated);<br /><br /> destructor(heapAllocated);<br /> free(heapAllocated);<br /> destructor(&stackAllocated);<br />}<br /></code></pre><br />Notes:<br /><ul><li>You can see now why <tt>new</tt> and <tt>delete</tt> are keywords rather than functions like <tt>malloc</tt> and <tt>free</tt>; what they do is actually a bit more complicated than a simple function call. The allocation and deallocation actually occur <em>inside</em> the constructor.</li> <br /><li>Note that the constructor initializes the function pointers (methods), but not the member variables. This is because methods are basically constant in C++, so that's entirely abstracted away from the programmer, but the member variables are more malleable and therefore aren't initialized (at least, this is the behavior on some older C++ compilers).</li><br /><li>Constructors and destructors in C are named like <tt>Object::Object</tt> and <tt>Object::~Object</tt>. If you looked at them separately, the obvious way to do this in C would be to name the functions <tt>Object</tt> and <tt>Object</tt>, but this causes a blatant name collision when you put the two together which is even worse when you consider that the name of the <tt>struct</tt> is <em>also</em> <tt>Object</tt>. I handled this in my example by naming the functions <tt>constructor</tt> and <tt>destructor</tt>, but this is just a temporary solution, since this will cause problems as soon as we define even one more class. We'll see how C++ handles this problem in the next post.</li></ul><br /><em>Next Post: Objects, Part 2: Inheritance and Name Mangling</em>Imagisthttp://www.blogger.com/profile/06175695035725315419noreply@blogger.com0