内联函数(Inline Functions)
内联函数(Inline Functions)
一、相关日志
C++与C的不同(一)
http://blog.163.com/zhoumhan_0351/blog/static/399542272010019115933109/
必须保证每一个定义了静态对象的函数只有一个定义,故不能把定义了静态对象的函数作为内联函数。
定义一个友元函数为内联函数,不会改变其友元状态,而且它仍是全局函数。
只有类的成员函数才能说明为虚函数,普能函数不行;静态成员函数不能是虚函数;内联函数不能是虚函数,即使虚函数在类的内部定义,编译时仍将其视作非内联的;析构函数可以是虚函数,而且通常声明为虚函数。
C++基础笔记(二)
http://blog.163.com/zhoumhan_0351/blog/static/39954227201012471245444/
C++基本概念(内联,模板,函数)
http://blog.163.com/zhoumhan_0351/blog/static/39954227201002202430247/
二、内联函数
1、关键点
为了既保证预处理器的效率又增加安全性,同时还能像成员函数一样可以在类中访问,C++引入内联函数。
对于任何函数,编译器在它的符号表里放入函数类型(函数原型及返回值)。当编译器看到内联函数且对内联函数的分析没有发现错误时,就将对应于函数体的代码也放入符号表中。我们可以看到,编译器是对内联函数进行类型检查和转换的(在调用中,如果发现类型不匹配,则试图将其转换为正确类型,返回值类型也进行分析,如果类型不匹配,也尝试转换),而预处理宏是不行的。
假如要显式地或隐式地取函数地址,编译器也不能执行函数。只在在类声明结束后,其中的内联函数才会被计算。
//: C09:EvaluationOrder.cpp
// Inline evaluation order
class Forward {
int i;
public:
Forward() : i(0) {}
// Call to undeclared function:
int f() const { return g() + 1; }
int g() const { return i; }
};
int main() {
Forward frwd;
frwd.f();
} ///:~
所以,如上程序也可运行通过,虽然g()在f()这前还没有定义。
在类外定义的成员函数想成为内联函数时,只要加上inline就可以了。
2、预处理器的更多特征
预处理器的如下二个特例,内联函数不能代替:
1)字符串定义、拼接
字符串定义的完成是用#指示,它容许取一个标志符并把它转化为字符串数组。
#define DEBUG(x) cout << #x " = " << x << endl
int main()
{
int x=1;
DEBUG(x);
return 1;
}
前面已有叙述,相关日志。
Thinking in C++前几章笔记(一)
http://blog.163.com/zhoumhan_0351/blog/static/39954227201032124942513/
2)标志粘贴
可以直接用"##"实现。允许设两个标识符并把它们粘贴在一起自动生成一个新的标识符。
#include "iostream"
using namespace std;
#define FIELD(a) char* a##_string; int a##_size
#define FIELD(a) char* a##_string; int a##_size
class Record {
FIELD(one);
FIELD(two);
FIELD(three);
// ...
};
int main(){
Record m;
m.
}
3、一个常用的断言程序
//: :require.h
// Test for error conditions in programs
// Local "using namespace std" for old compilers
#ifndef REQUIRE_H
#define REQUIRE_H
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <string>
inline void require(bool requirement, const std::string& msg = "Requirement failed"){
using namespace std;
if (!requirement) {
fputs(msg.c_str(), stderr);
fputs("\n", stderr);
exit(1);
}
}
inline void requireArgs(int argc, int args, const std::string& msg = "Must use %d arguments") {
using namespace std;
if (argc != args + 1) {
fprintf(stderr, msg.c_str(), args);
fputs("\n", stderr);
exit(1);
}
}
inline void requireMinArgs(int argc, int minArgs,const std::string& msg ="Must use at least %d
arguments") {
using namespace std;
if(argc < minArgs + 1) {
fprintf(stderr, msg.c_str(), minArgs);
fputs("\n", stderr);
exit(1);
}
}
inline void assure(std::ifstream& in, const std::string& filename = "") {
using namespace std;
if(!in) {
fprintf(stderr, "Could not open file %s\n",
filename.c_str());
exit(1);
}
}
inline void assure(std::ofstream& out, const std::string& filename = "") {
using namespace std;
if(!out) {
fprintf(stderr, "Could not open file %s\n",
filename.c_str());
exit(1);
}
}
#endif // REQUIRE_H ///:~
//: C09:ErrTest.cpp
//{T} ErrTest.cpp
// Testing require.h
//#include "../require.h"
#include <fstream>
using namespace std;
int main(int argc, char* argv[]) {
int i = 1;
require(i, "value must be nonzero");
requireArgs(argc, 1);
requireMinArgs(argc, 1);
ifstream in(argv[1]);
assure(in, argv[1]); // Use the file name
ifstream nofile("nofile.xxx");
// Fails:
//! assure(nofile); // The default argument
ofstream out("tmp.txt");
assure(out);
} ///:~
输入输出流(二)
http://blog.163.com/zhoumhan_0351/blog/static/39954227201003005237697/
参考:
1、Thinking in C++