温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

API的设计方法是什么

发布时间:2021-10-25 11:31:22 来源:亿速云 阅读:133 作者:iii 栏目:开发技术

本篇内容主要讲解“API的设计方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“API的设计方法是什么”吧!

假设提供TestFun作为一个对外接口,我们编译并制作为静态库:

$ g++ -c api.cc -I./ $ ar -rcs libapi.a api.o

关于静态库的制作,请参考《Linux下如何制作静态库?》。

另外一个程序main.cc这么使用它:

// 来源:公众号编程珠玑 // 作者:守望先生 #include "api.h" int main(){     Param param;     param.num = 10;     param.str = "24";      TestFun(param);     return 0; }

编译链接使用:

$ g++ -o main main.cc -L./ -lapi -I ./ $ ./main

看起来并没有什么问题,有新的参数,可以直接在Param中增加即可,扩展性也不错。

问题来了

目前来看是没有什么问题的,但是假设,还有另外一个库要使用它,例如:

// 来源:公众号编程珠玑 // 作者:守望先生 // use_api.h #include"api.h" void UseApi();  // use_api.cc #include"use_api.h" void UseApi(){     Param param;     param.num = 10;     param.str = "24";      TestFun(param); }

也将它作为静态库:

$ g++ -c use_api.cc -I./ $ ar -rcs libuse_api.a use_api.o

这个时候同样主程序会用到我们的原始api,但是却使用了不同的版本,比如,新增了Param中新增了一个字段ext:

// 来源:公众号【编程珠玑】 // 作者:守望先生 // api.h #include<iostream> struct Param{     int num;     std::string str;     std::string ext; }; void TestFun(const Param &param);  // api.cc #include "api.h" void TestFun(const Param &param){     std::cout<<"num:"<<param.num<<" str:"<<param.str.c_str()<<" ext:"<<param.ext.c_str()<<std::endl; }

重新生成静态库:

$ g++ -c api.cc -I./ $ ar -rcs libapi.a api.o

这个时候,通过use_api使用api接口,但是链接新的库:

// 来源:公众号编程珠玑 // 作者:守望先生 #include "use_api.h" int main(){     UseApi();     return 0; }

这个时候,再去编译链接,并运行:

$ g++ -o main main.cc -I./ -L./ -luse_api -lapi $ ./main Segmentation fault (core dumped)

看到没有,喜闻乐见的core dumped了,分析core还会发现,是由于访问非法地址导致的。

我们再来梳理一下这个过程:

  • 提供库libapi.a版本A

  • libuse_api使用版本A进行编译,使用A版本的头文件

  • libapi.a库升级到B版本,其中头文件中增加了字段,并且实现也引用了新的字段

  • 主程序使用了use_api,但是链接了版本B的libapi.a库

这个时候,版本B的实现访问了新的字段,还是use_api中还是使用A版本,并没有传入新字段,因此自然会导致非法访问。

如何解决?

很简单,不直接暴露成员,而是提供setter和getter,而提供方式和前面提到的PIMPL方法类似。

// api.h // 来源:公众号编程珠玑 // 作者:守望先生 #include<iostream> #include<memory> class Param{ public:     void SetNum(int num);     int GetNum() const;     void SetStr(const std::string &str);     std::string GetStr() const;     void SetExt(const std::string &str);     std::string GetExt() const;     Param();   private:     class ParamImpl;     std::unique_ptr<ParamImpl> param_impl_; }; void TestFun(const Param &param);

在这里头文件中只提供setter和getter,而完全不暴露成员,具体成员的设置在ParamImpl中实现:

// api.cc // 来源:公众号编程珠玑 // 作者:守望先生 #include "api.h" class Param::ParamImpl{   public:     int num;     std::string str;     std::string ext; }; Param::Param(){     param_impl_.reset(new ParamImpl); } // 析构函数必须要 Param::~Param() = default; void Param::SetNum(int num){     param_impl_->num = num; } int Param::GetNum() const {     return  param_impl_->num; } void Param::SetStr(const std::string &str){     param_impl_->str = str; } void Param::SetExt(const std::string &ext){     param_impl_->ext = ext; } std::string Param::GetStr() const {     return param_impl_->str; } std::string Param::GetExt() const {     return param_impl_->ext; } void TestFun(const Param &param){     std::cout<<"num:"<<param.GetNum()<<" str:"<<param.GetStr().c_str()<<"ext:"<<param.GetExt().c_str()<<std::endl; }

通过上面的方式,不会直接暴露成员函数,而是提供接口设置或者获取,而在实现中,即便出现新的版本增加了接口,最多也只是获取到默认值,而不会导致程序崩溃。

到此,相信大家对“API的设计方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

api
AI