C++进阶 - 函数特性总结(重载与内联)
2017-07-20 19:32
302 查看
个人之言,请持怀疑态度参考。
C++有重载、内联、const和virtual 四种新的机制。本篇博客主要探究重载与内联。const用发可以参考我的另外一篇文章 点击这里
重载和内联机制,既可以用于全局函数也可用于类的成员函数;const 、virtual机制仅仅用于类的成员函数
重载
重载如何实现
通过函数的接口 - 参数 来区分。为什么不用返回值?因为返回值不可以100%保证区分。例如:void fun(int a); int fun(int a); /******************/ fun(10);
上述,调用fun 谁知道你调用的是哪个? 在C/C++C程序中是可以忽略返回值的
编译器根据内部标识符来区分重载函数。编译器会根据参数为每个重载函数生成不同的内部标识符。 (类似与 _fun_int )
C语言是没有重载的,如果用要在C++中调用已经被编译后的C库,应该使用
extern "C" { 函数或者其他C头文件 }
告诉C++编译器,函数是C链接,应该按照 C 的函数标识符查找,而不是C++
注意:C++编译器开发商已经对C标准库的头文件做了extern “C” 处理,所以我们可以直接引用。
并不是函数名字相同就能构成重载,必须有函数作用域相同的前提条件
隐式转换导致重载函数产生二义性
int func(int a) { cout << "int a" << endl; return 0; } int func(float a) { cout << "float a" << endl; return 0; } int main() { func(0.5); getchar(); return 0; }
上面的代码看起来似乎很合情理,但是编译器会报错( error C2668: “func”: 对重载函数的调用不明确)。原因在于0.5 既可以匹配double 又可以通过隐式转换成 int 。
成员函数的重载、覆盖(重写)、隐藏
对照表重载 | 覆盖(重写) | 隐藏 | |
---|---|---|---|
范围 | 相同的范围,在同一个类中 | 不同的范围,位于派生类和基类中 | 不同的范围,位于派生类和基类中 |
函数名字 | 相同 | 相同 | 相同 |
参数 | 不同 | 相同 | 不同【相同】 |
基类virtual关键字 | 可有可无 | 必须有 | 可有可无【没有】 |
举个例子来说明:
#include <iostream> using namespace std; class A { public: A(){}; ~A(){}; /*重载*/ void dis(int a) { cout <<"_dis_int"<< endl; } void dis(char a) { cout << "_dis_char_" << endl; } /*覆盖(重写)*/ virtual void func(int a) { cout << "基类func" << endl; } /*隐藏*/ void fun() { cout << "我在基类中 fun" << endl; } virtual void fun_c() { cout << "我在基类中 fun_c" << endl; } private: }; class B :public A { public: B(){}; ~B(){}; virtual void func(int a) { cout << "派生类func" << endl; } void fun() { cout << "我在派生类中 fun" << endl; } void fun_c(int a) { cout << "我在派生类中 fun_c" << endl; } private: }; int main() { A a; B b; /*使用重载*/ a.dis('a'); a.dis(10); /*使用(覆盖)重写*/ a.func(1); b.func(2); /*隐藏 试着解释一下运行结果 */ a.fun_c(); b.fun_c(10); a.fun(); b.fun(); /*猜猜这个结果是什么?*/ B* bb = &b; A* aa = &b; aa->func(1); bb->func(2); aa->fun(); bb->fun(); getchar(); return 0; }
如果你亲自运行过上面的代码,一定会发现 aa->fun(); 结果和你想的不一样,哈哈 ,这就是坑。被隐藏函数的行为取决于指针的类型!!
隐藏存在的意义(了解就好了,写代码还是要避免这么烦人的隐藏): 解决多继承的问题,比如一个类有多个基类,有时也搞不清楚那些基类定义了fun(),直接隐藏就好了,哈哈,自己都给写迷糊了的代码估计是在写BUG.
函数内联
用内联取代宏代码
宏代码的优点:预处理器用复制宏代码的方式代替函数调用,省去了参数压栈,call调用、参数返回、执行return等步骤(ps:可以去了解一下C/C++翻译成汇编语言后的执行细节),提高了速度。
缺点:
容易掉坑里!哈哈。预理器无脑复制宏代码常常出现一些边际效应如优先级错误等等;还有就是没法操作类的私有成员,这在C_++中是致命的。
内联函数如何工作
如果编译器检查没有发现内联函数有错误,那么他除了会把函数声明放在符号表中,还会把函数的代码也一并放入符号表。在调用内联函数时,编译器会像执行普通函数一样进行类型安全检查、自动类型转换等等。如果检查没有错误,内联代码就会直接替换函数的调用,省去的函数调用的开销,而且还进行了类型检查。内联的特点
inline是一个‘用于定义式的关键字’,而不是想其他关键字一样‘用在声明式’。如果你想把一个函数变成内联函数,在函数声明前加
inline是没什么卵用的!(如果你还弄不清神马是定义式,神马是声明式,那么你需要赶快充电了)
inline只是对编译器的一个申请,不是强制命令。也就是说你写的函数能不能成为内联函数不是你说了算,最后还的由编译器综合考虑才决定能不能内联
申请可以隐式的提出。将函数定义在类的定义式内其实就是在暗示编译器,来给我把这个函数弄成内联吧。
内联的代价就是造成程序的体积膨胀,导致执行效率减低。所以
inline只是申请,由编译器来优化决定。其次,申请成为内联的函数应该尽可能的小(没有循环,递归等等重量级的操作)。
内联函数如果修改,将导致该函数的使用者重新编译!在编译一个项目是,其实并不是每次都要把代码全部编译,好的代码设计在大多数情况下仅仅重新链接就好了。如果你要设计一个库,那么你一定要慎重考虑。
大部分调试器对内联函数是没法调试的。因为内联函数直接将本体编进了程序,实际上这个函数并不存在,自然也没法跟踪调试了。(ps:内联函数是没法取到函数地址的)
有时侯编译器在进行内联的时候,还可能产生内联函数的本体。
inline void f(){} void ( * ps)() =f; f(); //会被内联 ps(); //不会被内联
前提是编译器同意对f() 采用内联策略
程序中要取f()的地址,编译器会生成一个内联的本体,毕竟不肯呢给你>随便编造一个地址出来。
SO 编译器通常不会对通过指针调用的函数实施内联大法。 正常调用的话还是会被内联的,比如上面代码中 f(); 直接调用。
内联函数的误区
类的构造析构函数使用内联更有效这个想法是错误的!类的构造析构函数看起来没做什么事,其实是编译器把所有细节隐藏了!C++对‘对象的创建和销毁做了各种保证’,而且对象允许多种方式创建。这些行为其实都是在编译是,编译器自动把代码插在了构造器和析构器中,至少不会凭空发生。
内联函数用的越多越好
错,从他的特性可以看出是要谨慎使用的
最后一段补充 80 - 20经验法则
程序往往把80%的时间化在20%的代码上。我们要做的是找出20%去优化,而不是瞎折腾其他没有什么影响的代码软件开发根据我的个人经验,当效率不是问题的瓶颈时,更应考虑软件的整体逻辑,而不是抓着某一点死磕到底。所以内联只有在优化阶段需要优化效率时才考虑。
我的个人网站 http://www.breeziness.cn/
我的CSDN http://blog.csdn.net/qq_33775402
转载请注明出处 小风code www.breeziness.cn
相关文章推荐
- c++之函数特性 重载 内联 函数默认值
- C++总结2——函数的重载
- C++和Java在 子类继承父类时,两者成员函数重写和重载的特性
- C++ 函数重载 总结
- 第八章 C++函数的高级特性(8.3 参数的缺省值 8.4 运算符重载 8.5 函数内联)
- C++的缺省参数与函数重载是正交特性吗?
- C++语言特性:构造函数,析构函数,虚函数,内联函数,静态成员函数,重载,覆盖,隐藏
- 【C++】内联inline、继承、重载与虚函数的解释
- C++函数的高级特性-函数重载
- 用C语言来实现的类似C++函数的重载特性-----void*指针闲谈
- C++进阶—>函数重载、重写、重定义的区别
- C++的缺省参数与函数重载是正交特性吗?
- C/C++日常学习总结(第六篇)多基派生引起的虚函数访问二义性问题&重载,覆盖,隐藏的区别
- imooc 学习总结——离港篇:C++函数新特性
- C++和Java在 子类继承父类时,两者成员函数重写和重载的特性
- 第八章 C++函数的高级特性(8.2 成员函数的重载、覆盖与隐藏)
- [C++学习笔记]--内联函数、函数重载、函数defualt参数
- C++ 中string.find() 函数的用法总结
- C++ 中assert()函数用法总结
- [C/C++]函数重载、作用域、隐藏