当前位置:   article > 正文

C语言模拟C++对函数和变量的封装_如何用c封装c++函数

如何用c封装c++函数

C++的方法和成员变量都是放在类里面的,通过类的实例化来访问其中的方法和成员,C++甚至还引入了命名空间,通过命名空间访问类,再实例化类。C语言也可以模拟C++的对类的封装,通过编码规范来实现,或者说,定了一套编码框架,按照这个框架来做,就可以实现封装。
先来看下面一段C代码。

/*mathOpr.c*/
#include<stdio.h>
int add(int data1, int data2)
{
    return data1 + data2;
}
int sub(int data1, int data2)
{
    return data1 - data2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这段代码,定义了2个函数,add和sub,其他文件可以直接访问这2个函数,比如下面的代码。

/*main.c*/
#include <stdio.h>
#include "mathOpr.c"
int main(int argc, char *argv[])
{
    int ret = add(1, 2);
    printf("%d\n", ret);
    ret = sub(4, 3);
    printf("%d\n", ret);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

gcc -o main main.c
./main
在这里插入图片描述
我现在要把mathOpr.c封装,再加个mathOpr.h文件。

.h文件

/*mathOpr.h*/
#ifndef __MATH_OPR_H
#define __MATH_OPR_H
#include <stdio.h>
/*封装函数,这2个函数也可以直接被调用*/
int add(int data1, int data2);
int sub(int data1, int data2);

/*定义封装函数结构体*/
typedef struct{
    int (*add)(int data1, int data2);
    int (*sub)(int data1, int data2);
} MathOprFunc;

/*封装函数变量*/
static MathOprFunc m_mathOprFunc = 
{
    .add = add,/*指向上面的add函数*/
    .sub = sub /*指向上面的sub函数*/
};
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

.c文件,在原来基础上,加上include上面的.h文件

/*mathOpr.c*/
#include<stdio.h>
int add(int data1, int data2)
{
    return data1 + data2;
}
int sub(int data1, int data2)
{
    return data1 - data2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

main.c文件,注意看,是#include “mathOpr.h”,而不是#include “mathOpr.c”

/*main.c*/
#include <stdio.h>
#include "mathOpr.h"
int main(int argc, char *argv[])
{
    int ret;
    ret = m_mathOprFunc.add(1, 2);/*通过封装变量m_mathOprFunc访问add函数*/
    printf("%d\n", ret);
    ret = m_mathOprFunc.sub(4, 3);/*通过封装变量m_mathOprFunc访问sub函数*/
    printf("%d\n", ret);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

现在,不是直接编译成main可执行文件,而需要先把mathOpr.c编译成mathOpr.so,再把mathOpr.so作为main.c的编译文件。
#编译mathOpr.c
gcc -c mathOpr.c
#生成mathOpr.so
gcc -fpic -shared -o mathOpr.so mathOpr.o
#编译成main可执行文件
gcc -o main main.c mathOpr.so
#执行
./main
在这里插入图片描述
得到的结果和上面的一样。
为了实现封装,加了很多代码,而且编译过程也复杂了,感觉没必要进行封装了。但是,正如我当初学C语言,觉得C语言没啥用,1+1,我用计算器就可以算出来,没必要写那几行代码。当一个代码文件达到了数百行,甚至上千行,并且代码文件的函数有几十个,对函数和变量的封装就有必要了,有兴趣的可以用C++做同样的封装,代码量是差不多的。
一开始就提到,通过编码规范来实现封装,mathOpr.h里面的注释也提到,可以直接调用add和sub函数,万一其他代码文件也有类似功能的函数,命名也一样,那就会冲突了。所以,就通过命名规范(属于编码规范的内容)来区别,在所有的变量/结构体/函数前加上文件名称,在.h文件有体现,MathOprFunc和m_mathOprFunc就是,修改后的的.h文件和.c文件如下

/*mathOpr.h*/
#ifndef __MATH_OPR_H
#define __MATH_OPR_H
#include <stdio.h>
/*封装函数,这2个函数也可以直接被调用*/
int mathOprAdd(int data1, int data2);
int mathOprSub(int data1, int data2);
/*定义封装函数*/
typedef struct{
    int (*add)(int data1, int data2);
    int (*sub)(int data1, int data2);
} MathOprFunc;
/*封装函数变量,用add代替mathOprAdd,sub代替mathOprSub*/
MathOprFunc m_mathOprFunc = 
{
    .add = mathOprAdd,
    .sub = mathOprSub
};
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
/*mathOpr.c*/
#include<stdio.h>
int mathOprAdd(int data1, int data2)
{
    return data1 + data2;
}
int mathOprSub(int data1, int data2)
{
    return data1 - data2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

main.c不需要改动,此时,通过访问m_mathOprFunc.add来访问mathOprAdd函数,这里看到封装的痕迹了吧。
这种封装,会不会损耗性能呢,封装前是直接访问函数,封装后是通过变量来访问函数指针,达到访问函数的目的。可以直接的说,性能损耗是肯定的,因为多做了动作,但是,可以通过在m_mathOprFunc变量前加static,再编译时加-O3级别优化,性能是没有损失的,编译器的优化可以做到直接用mathOprAdd来替换m_mathOprFunc.add。同时,相对函数实现功能的耗时来说,访问函数的耗时微不足道,除非像这里的很简单的功能,有兴趣的可以写代码测试一下。
上面说的是封装函数,接下来是封装变量。
代码可能会用到全局静态变量,仅限于当前代码使用,比如static int giTmp;下面3个代码文件是示例
.h文件

/*mathOpr.h*/
#include <stdio.h>
/*定义封装变量结构体*/
typedef struct
{
    int data1;
    int data2;
} MathOprVar;
/*初始化封装变量*/
static inline MathOprVar mathOprVarInit()
{
    MathVar var = 
    {        
        .data1 = 10,
        .data2 = 20
    };
    return var;
}
/*封装函数,这2个函数也可以直接被调用*/
int mathOprAdd(MathOprVar *var);
int mathOprSub(MathOprVar *var);
/*定义封装函数*/
typedef struct
{    
    int (*add)(MathOprVar *var);
    int (*sub)(MathOprVar *var);
} MathOprFunc;
/*封装函数变量,用add代替mathOprAdd,sub代替mathOprSub*/
static MathOprFunc m_mathOprFunc = 
{    
    .add = mathOprAdd,
    .sub = mathOprSub,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

.c文件

/*mathOpr.c*/
#include "mathOpr.h"
#include <stdio.h>
int mathOprAdd(MathVar *var)
{
    return var->data1 + var->data2;
}
int mathOprSub(MathVar *var)
{
    return var->data1 - var->data2;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

main.c

#include "mathOpr.h"
#include <stdio.h>
int main(int argc, char *argv[])
{    
    MathOprVar var = mathOprVarInit();/*调用变量初始化函数*/
    printf("%d %d\n", m_mathOprFunc.add(&var), m_mathOprFunc.sub(&var));
    MathOprVar var2 = {12,23}; /*自己定义初始化的值*/
    printf("%d %d\n", m_mathOprFunc.add(&var2), m_mathOprFunc.sub(&var2));
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

从.h文件可以看到,多了结构体MathOprVar和函数mathOprVarInit。其中,结构体MathOprVar可以看作C++里面的类,而函数mathOprVarInit可以看作是构造函数,还可以加个mathOprRelease作为析构函数。
看main.c里面,可以用MathOprVar定义不同的变量,而且操作起来互不影响,因为,都是从参数传入的,并且操作的都是参数变量。由于每个函数都必须传入MathOprVar变量,这个变量当作不同函数交流的媒介,可以当作全局变量用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/392618
推荐阅读
相关标签
  

闽ICP备14008679号