[原创]面向对象语言的编译过程--以C++为例(一)

摘要:

概述面向对象语言的重要概念和实现技术

以C++语言为例,介绍如何将C++程序翻译成C程序

实际的编译器大都把C++程序直接翻译成低级语言程序

    关于面向过程的高级语言的编译过程想必大家不陌生。《编译原理》类的课程多是以C语言(C的子集)为例,介绍高级语言的编译过程。但是自从面向对象语言产生以来(I love OO programming,yeah),面向对象的编程语言明显在编程语言中占据了主流的位置。面向对象的编程语言有三个明显的特点:封装(Encapsulation),继承(Inheritance),和多态(Polymorphism)——以上是一道常见的面试题,各位童鞋请注意。最初的面向对象语言往往只提供部分的面向对象特性,比如VB(oh,I love VB so much)。

    面向对象的三个特性给代码复用带来的极大的好处,同时也改变了程序员的理念,使逻辑开发更接近于现实世界,而面向对象从根本上说是一种世界观,是对现实世界的一种认识方式,扯远了。

    那么编译器是如何理解这三个特性的呢?我们以C++为例,看编译器如何把面向对象的程序翻译成面向过程的程序,也就是把C++翻译成C语言,实际的编译器往往直接把C++程序翻译成低级语言,但是也有特例,比如ObjectC,就是把C++翻译成C语言,而以C语言(或C语言的子集,不甚了解)作为中间代码的。

    翻译的过程如下:

    1. 将C++语言中一个类的所有非静态属性构成一个C语言的结构体类型,取类的名字作为结构体类型的名字

    2. 类的静态属性是该类的所有对象所共有的,应当翻译成C中的全局变量,但是需要改一个名字

    3. C++语言中类的对象声明不加翻译就成了C语言中相应结构体类型的变量声明

    4. 将C++语言中类的非静态方法翻译成C语言的函数,对应的方法和函数的区别有下面几点:

          函数的名字必须在原来方法名的基础上修改

          函数声明增加一个形参this

          在函数体中出现的函数调用也要增加一个实参

          在方法中对本对象的非静态属性的访问,改成对this相应域的访问。在方法中对其它对象的非静态属性的访问不必修改

    5. 类的静态方法在定义和调用的地方都需要改名

    我们举一个例子,以下是一个简单的面向对象的程序,主要体现了面向对象的封装特性:

#include <iostream>

using namespace std;

class Test

{

public:

//一个静态变量

static int c;

int a;

static void printc();

void printa();

};

int Test::c;//静态变量初始化

void Test::printc()

{

cout<<c<<endl;

} 

void Test::printa()

{

cout<<a<<endl;

}

int main()

{

Test t;

t.a=1;

Test::c=2;

t.printa();

Test::printc();

return 0;

}

-------------------------------------------偶是华丽的分割线--------------------------------

    以下是翻译之后的C语言版本,这里的C语言版本放到C99的编译器里不能直接运行,因为其中类似Test t;的写法是C++的,C语言中需要写成struct Test t;这里这么写只是为了看起来明晰。
-------------------------------------------偶是华丽的分割线--------------------------------

#include <iostream>
using namespace std;
int Test_c;//静态变量翻译成全局变量,但是需要改名
struct Test//类翻译成结构体
{
int a;//成员变量不变
};
void Test_printc()//方法改名,静态方法基本不变
{
cout<<Test_c<<endl;
}
void Test_printa(Test& th)//方法改名,成员函数加一个参数
//(此处应为this指针,但是this关键字为编译器保留字,用th代替)
{
cout<<th.a<<endl;//对成员函数的引用变为对this域中相应变量的引用
}
int main()
{
Test t;//类变量声明不加翻译就成了C语言中相应的结构体类型的变量声明
t.a=1;//对类成员函数的引用不变
Test_c=2;//静态变量的引用变为对全局变量的引用
Test_printa(t);//对类成员函数的引用传入对象作为参数
Test_printc();//对类静态成员函数的引用改成直接对函数的引用
return 0;
}

总结:
    本文介绍了面向对象语言的特性,通过封装特性介绍了编译器对面向对象语言的翻译过程,以一段简单的程序解释了C++语言向C语言的编译过程。由此我们可以得到如下启示:
    静态变量可作为全局变量理解
    类的成员函数类似于一种映射,编译之后编译器会为成员函数增加一个对当前对象的引用,从而把对成员变量的引用变为对this域的引用,并且更改所有成员函数的引用处
    编译器会对成员函数,静态成员函数和静态成员改名,不同的编译器对此的处理不一样,我记得微软的编译器是在类名之后加@@,所以我们如果看到LinkError的话都会从错误信息中看到一串陌生的函数名,实际就是编译器在处理封装之后的结果。

    下一篇文章我们会结合面向对象继承和多态的特性对面向对象语言翻译过程进行分析,不要走开,精彩继续。

posted @ 2010-08-13 13:35  HarryChenThu  阅读(1400)  评论(0编辑  收藏  举报