跳到主要内容

函数

声明

A Function is a block of code or program segment that is defined to perform a specific well-defined task. A function is generally defined to save the user from writing the same lines of code again and again for the same input. All the lines of code are put together inside a single function and this can be called anywhere required. main() is a default function that is defined in every program of C++.

syntax :

FunctionType FunctionName(parameters);

inline function

C++语言新增关键字 inline,用于将一个函数声明为内联函数。在程序编译时,编译器会将内联函数调用处用函数体替换,这一点类似于 C语言中的宏扩展。

采用内联函数可以有效避免函数调用的开销,程序执行效率更高。使用内联函数的缺点就是,如果被声明为内联函数的函数体非常大,则编译器编译后程序的可执行码将会变得很大。另外,如果函数体内出现循环或者其它复杂的控制结构的时候,这个时候处理这些复杂控制结构所花费的时间远大于函数调用所花的时间,因此将这类函数声明为内联函数的意义不大,反而会使得编译后可执行代码变长。

在程序设计过程中,我们通常会将一些频繁被调用的短小函数声明为内联函数。

为了使得 inline 声明内联函数有效,我们必须将 inline 关键字与函数体放在一起才行,否则 inline 关键字是不能成功将函数声明内联函数的。如例 1 所示,inline 关键字则无丝毫作用,而例 2 中则成功将 swap() 函数声明为了一个内联函数。

void swap(int &a, int &b);
inline void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}

// 声明1(加 inline,建议使用)
inline int functionName(int first, int secend,...);

// 声明2(不加 inline)
int functionName(int first, int secend,...);

// 定义
inline int functionName(int first, int secend,...) {/****/};

// 类内定义,隐式内联
class A {
int doA() { return 0; } // 隐式内联
}

// 类外定义,需要显式内联
class A {
int doA();
}
inline int A::doA() { return 0; } // 需要显式内联

相当于把内联函数里面的内容写在调用内联函数处;

相当于不用执行进入函数的步骤,直接执行函数体;

相当于宏,却比宏多了类型检查,真正具有函数特性;

不能包含循环、递归、switch 等复杂操作;

在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数。

编译器对inline函数的处理步骤

将 inline 函数体复制到 inline 函数调用点处;

为所用 inline 函数中的局部变量分配内存空间;

将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;

如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用 GOTO)。

优点

  1. 内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度。
  2. 内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。
  3. 在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。
  4. 内联函数在运行时可调试,而宏定义不可以。

缺点

  1. 代码膨胀。内联是以代码膨胀(复制)为代价,消除函数调用带来的开销。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
  2. inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译,不像 non-inline 可以直接链接。
  3. 是否内联,程序员不可控。内联函数只是对编译器的建议,是否对函数内联,决定权在于编译器。
虚函数virtual可以使inline函数吗?

虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。

内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。

inline virtual 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 Base::who()),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。

function

声明 declaration

  1. 声明:是指出存储类型,并给存储单元指定名称。

  2. 定义:是分配内存空间,还可为变量指定初始值。

  3. extern关键字:通过使用extern关键字声明变量名,而不是定义它。

声明不一定是定义:extern声明没有分配内存空间,所以不是定义;extern告诉编译器变量在其他地方定义了。定义也是声明:定义变量的时候,同时给变量指出了存储类型,并给变量的存储单元指定了名称,所以也是声明。

声明有指定初始值:如果指定了初始值,即使前面加了extern关键字,也是定义。

函数原型(又称函数声明):函数原型之于函数,相当于变量声明之于变量,只有函数头的就是函数原型。函数定义:带有函数体的就是定义,函数原型的返回值类型与函数定义必须相同。函数原型的形参表的类型与顺序必须与函数定义相同,但是函数原型可以不写形参名称,即便写了形参名称也可以和原函数不一样。

Elem* next_elem();
void next_elem(int);
double next_elem(double);

在函数被调用之前必须先有函数原型,函数定义可以放在调用函数的后面。

int func(); // 必须在调用函数的前面

int main() { int ret = func(); }

int func() { return 0; } 可以在调用函数的后

函数声明也可以包含参数名。有助于读者理解程序的含义。但实际上,除非该声明同时也是函数的定义。否则编译器会简单忽略参数名。

double get(const vector<double>& vec,int index);
//

member functions in class

char& String::operator[](int index);

function overloading

函数重载:如果程序中存在名字相同但参数类型不同的函数,则编译器会为每次调用选择最恰当的版本.

void print(int);
void print(double);
void print(string);

void user(){
print(42);
print(9.65);
print("hello world");
}
Loading Comments...