frankfan的胡思乱想

学海无涯,回头是岸

函数重载与内联

命名空间 函数重载 内联函数

本章讲授的主要 内容是命名空间、函数重载以及内联函数,这三个相对于C语言,都是C++独有的。并且都是为了解决C语言无法解决或者优雅解决的问题而存在的。

命名空间

C/C++是编译型语言,在编译后会将源码中定义的变量名或者函数名等变成唯一的符号名,这个符号是独一无二的,这一过程又被称作命名倾轧 ,源码中相同作用域下的同名变量在命名倾轧后生成的符号必然相同,这样在大型工程或者多人合作的项目中是很难避免在统一作用域内定义有同名变量名,所以在没有命名空间的C语言中通常通过定义唯一的名称来规避这种情况。

而C++则提出命名空间的概念,用来避免这种情况的发生。

#include <iostream>

namespace mySpace{
  int value;
  void modify(){
    value = 12;
  }
}
int main(){
  
  //虽然有两个value变量,当一个value是main函数中的局部变量,另一个是全局作用域下的value变量。
  int value = 11;
  
	mySpace::modify();
  cout<<mySpace::value<<endl;//输出12;此处的value是全局变量
  return 0;
}

创建了命名空间后,那么在使用命名空间中变量或者函数时,都需要带上命名空间的前缀,否则无法使用。

而此外C++也提供另一个命名空间的使用方式using namespace mySpace 这样在此之后使用mySpace命名空间中的变量和函数时就不再需要额外指定命名空间了。

其优势在于减少代码编写量,但其缺点在于有可能在两个不同的命名空间下存在相同的变量名,那么这样就会产生冲突,编译错误。

#include <iostream>

//两个不同的命名空间,但是存在两个同名变量。这两个命名空间可能出自两个不同人之手,位于不同的文件中,而当这两个命名空间在同一个文件中使用时,就不能直接使用using namespace了
namespace mySpace{
  int value;
  void modify(){
    value = 12;
  }
  
  int value2;
}

namespace yourSpace{
  int value;
  void modify(){
    value = 11;
  }
}

using namespace mySpace;
using namespace yourSpace;

int main(){
  //modify();直接使用,编译错误
  mySpace::modify();
  yourSpace::modify();
  value2 = 12;//直接使用
  return 0;
}

只能创建全局的命名空间或者在命名空间内部创建命名空间,不能在函数中创建命名空间

#include <iostream>
namespace mySpace{
  int value = 11;
  namespace mySpace2{
    int value = 12;
  }
}

int main(){

  cout<<myspace::value<<endl;//11
  cout<<myspace::myspace2::value<<endl;//12
  return 0;
}

除了直接使用命名空间的名称外,还可以创建命名空间的别名。

namespace mySpace = superSpace superSpace就是mySpace的别名了。二者等价。

函数重载

C语言的命名倾轧不支持函数重载,而C++的函数是支持重载的,也就是允许同名函数的存在。

因为C++的命名倾轧机制对于生成的函数符号是依据函数名、函数参数类型、函数参数顺序、函数参数个数决定的,尽管函数名可能相同,但只要其他因素有不同就能生成不同的函数符号,这就是C++支持函数重载的本质。

#include <iostream>

int add(int a,int b){return a + b;}
float add(float a,float b){return a + b;}

int main(){

  add(11,22);//int add(int a,int b)
  add(11.0f,22.0f);//float add(float a,float b)
  
  //编译失败,因为11.1、22.2是double类型,以上两个add函数都满足其要求(double类型可以都强转为int或者float)
  //add(11.1,22.2); 二义性问题
  return 0;
}

内联函数

普通函数与内联函数在使用上并没有差异,差别在于内联函数会就地展开函数,而不会发生函数调用(函数调用需要额外的开辟栈帧)

这一点与宏似乎并没有差别,事实确实如此,不过内联函数相较于宏的好处在于支持调试。

#include <iostream>

inline void func(){
 //do something....   
}
int main(){

  //被inline关键字修饰的函数就是内联函数,内联函数不会真正的call,而是就地展开,这样就能节省调用时间。不过源代码体积会相应的增大。
  //此外还需要注意的是,递归函数是无法内联的
  func();
  return 0;
}

而有意思的事,微软的vs中,在测试模式下,函数的调用无论如何都会call,而不是内联(即使使用了inline),这是为了方便调试。

而在release模式下,则无论是否有inline,编译器都会根据情况对函数调用进行优化,有时即使没有使用inline关键词,函数调用也会内联化。当然,如果指定了inline,则肯定会内联(这个也是可以根据编译选项调整的)

此外还有一个需要注意的是,内联函数的作用域是文件作用域。

言外之意,当使用.h.cpp两个文件来拆开一个函数的声明与定义时,内联函数必须是定义在.h文件中,否则会链接出错。因为.cpp中定义的内联函数作用域只在.cpp文件中,外界无法使用。

posted on 2021-12-28 00:38  shadow_fan  阅读(64)  评论(0编辑  收藏  举报

导航