当前位置: 首页 > 科技观察

如何将C++的源代码重写成C代码?

时间:2023-03-15 14:07:47 科技观察

C++解释器比C语言解释器占用更多的存储空间。它希望在某些特定场合与C++代码兼容。同时,为了节省有限的存储空间,降低成本,提高效率,用C++语言编写的源程序需要用C语言重写。C++与C最大的区别在于C++中类的概念和特点。把C++改成C的问题就转化成了如何分类的问题。有两种方法:去除C++中面向对象的特性,先充分理解源代码的逻辑,再重写;保留C中一些面向对象的特性,用结构体实现类的功能。第一种方法适用于少量类。如果类的数量多,把所有的源码都看懂,再重写,很费时间,而且很容易出错。更何况,如果遇到一个大项目,完全看懂源码几乎是不可能的。下面就C++的一些特性以及如何在c中实现或替换进行初步探讨。解释:函数Ixx是类xx的构造函数的实现。原类的成员函数改为结构体名+'_'前缀的函数。函数指针U是原类析构函数的声明;U+结构名是原类析构函数的实现;Fun-_+结构体名称指向该结构体的成员函数指针;以上情况后面会遇到,不再赘述。1、类的成员函数和数据成员由于struct不控制成员的访问权限,必须额外增加访问控制的机制,使程序复杂化,所以只能放弃对访问权限的控制。C中类的数据成员可以直接转换为结构体的数据成员。函数需要转换为对应的函数指针,因为struct中不允许函数声明和定义。如果函数前有virtual、inline等修饰符,也要去掉,比如functionvoidfunca(inta);更改为void(*funca)(structB*p,inta);可以看到函数指针的原型添加了一个指向structB的指针的指针被创建了,因为类的成员必须在函数内部进行操作,而结构体的成员必须由指针指定。在类的成员函数中,实际上在参数列中隐含了一个指向自身的this指针。对于静态成员,必须定义为全局变量或全局函数,因为结构中不能有静态成员。2.类的构造函数类在实例化时会调用类的默认构造函数。在struct中,必须定义一个同名的函数指针,指向一个带有构造函数的初始化函数。与构造函数不同的是,它必须在初始化函数中添加一条语句来初始化函数指针。使用时,在创建结构体变量时使用malloc而不是new,此时手动调用初始化函数。如下例所示:classA{public:A();~A();voidfunc(inta);private:intb;};A::A(){b=0;}voidA::func(inta){b=a;}typedefstructclassAA;structclassA{void(*A)(structclassA*p);//构造函数指针void(*U)(structclassA*p);//析构函数指针void(*func)(structclassA*p,inta);intb;};voidfun_A(A*p){p->func=classA_func;//初始化函数指针}voidIA(A*p)//构造函数,命名规则加上I{fun_A(p);p->b=0;//原构造函数做的部分}voidclassA_func(A*p,inta){p->b=a;}使用方法如下:A*s=(A*)malloc(大小(A));s->A=IA;s->A(s);3.类的析构函数类的析构函数的工作是释放占用的资源。在C中,不管是什么struct,都是用函数指针U代替析构函数。之所以所有的struct都使用指针U是基于以下情况:如果子类指针赋值给基类指针,基类指针释放时不需要考虑调用哪个函数名的析构函数,只要调用成员函数U即可。成员函数U需要像一般的成员函数一样在fun_classname()函数中指定。类的析构函数由系统调用,在C中必须显式调用。至于什么时候调用,需要准确判断。四、类的拷贝构造函数类的拷贝构造函数的主要目的是在以下情况下加快类的构造:作为参数传递给函数。(additem(Item))作为函数返回值。作为实例化类时的参数。在这三种情况下,系统直接调用类的拷贝构造函数而不是构造函数。注:C=D;不调用复制构造函数,在这种情况下使用重载'='运算符的方法。(详见运算符重载);由于在C中定义struct变量时,使用的都是指针,不会使用拷贝构造函数,所以暂时不考虑。对于原来需要类变量的函数参数或返回值,必须全部转为类指针。在实例化一个类作为参数时,可以通过定义另一个带参数的构造函数来解决。5.类的内联函数和虚函数内联函数和虚函数的修饰符inline和virtual都要去掉。应该去掉内联函数体,将内联函数定义为外部函数。如:classB{...virturevoidfunb();inlineintadd()const{returna+b;};private:inta;intb;...}改为:typedefclassBB;structclassB{...void(*funb)(structclassB*p);int(*add)(structclassB*p);inta;intb;}voidclassB_funb(B*p){…}intclassB_add(B*p){returnp->a+p->b;}voidfun_classB(B*p){…p->funb=classB_funb;p->add=classB_add;}6、重载类中的重载有两种:函数重载和运算符重载:1)函数重载。参数的数量或类型不同。这样调用的时候会根据你输入的参数调用不同的函数。在C中,我们必须给它们取不同的名字,没有别的办法。2)运算符重载运算符重载只是为了满足一般使用运算符不出错的习惯。C不支持运算符重载,可以定义一个函数来实现这个功能。这是一个通用的类修改。七、类继承1)单继承如果类之间存在继承关系,首先按照通用的类修改方法修改基类。然后将基类的所有定义复制到子类的前面。除了将基类的构造函数名称更改为子类构造函数的名称外,不能对基类定义的部分进行其他更改。并在构造函数中调用基类的构造函数,然后如果子类重写了基类的函数,则必须将函数指针重定向到子类函数。这是为了保持类继承带来的动态链接特性。类之间的继承关系是复杂多变的。为了保证基类在所有的子类中是唯一的并且便于修改,最好的办法就是把基类的结构部分做成一个宏,在子类中直接使用就可以了。2)多重继承我个人认为最好不要使用多重继承,会带来一些问题,多重继承路径会有问题。除非是为了编程的方便,比如继承接口等。也可以修改多重继承。将多个基类的所有成员复制到子类中。如果遇到重复的成员名称,请添加前缀以区分它们。当然,这里指的是基类之间相同。如果派生类和基类之间存在重名,则基类将被覆盖。8.其他以上是C++中与C最不同,也是最常用的主要特点和修改方法。还有其他的,比如使用模板等,都是为了方便编程和代码重用。不是在C中,所以我必须编写多个函数来分别实现它们。另外,参数列表中的&符号要用指针代替,默认值也要去掉,调用时把默认值写进去。