C++底子

打印 上一主题 下一主题

主题 552|帖子 552|积分 1656

命名空间

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目标是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种题目标。
命名空间的概念

命名空间是一个声明地域,它可以将变量、函数、类等标识符组织在一起,形成一个独立的作用域。这意味着,在同一个程序中,差异命名空间内的标识符可以同名而不会产生冲突。
命名空间的作用


  • 避免命名冲突:在一个大型的项目中,差异的模块或库可能会使用类似的函数名或变量名,命名空间能够有用地避免这种冲突。
  • 提高代码的可读性和可维护性:通过将相关的标识符组织在同一个命名空间中,代码的布局更清楚,便于管理和维护。
命名空间的使用

界说命名空间

在C++中,使用namespace关键字来界说一个命名空间:
  1. namespace 名称 {
  2.     // 声明或定义变量、函数、类等
  3. }
复制代码
比方:
  1. namespace MyNamespace {
  2.     int add(int a, int b) {
  3.         return a + b;
  4.     }
  5. }
复制代码
访问命名空间中的成员

要访问命名空间中的成员,可以使用作用域解析操纵符::
  1. MyNamespace::add(5, 10);
复制代码
使用using声明

可以使用using关键字简化对命名空间成员的访问:
  1. using namespace MyNamespace;
  2. add(5, 10); // 直接使用函数名,无需加命名空间前缀
复制代码
使用匿名命名空间

匿名命名空间是一种特别的命名空间,它没有名字,通常用于隐藏只在当前源文件中使用的函数、变量和范例。在匿名命名空间中声明的全部元素都自动成为该源文件的局部命名空间的一部门:
  1. namespace {
  2.     int hiddenVariable = 42;
  3.     void hiddenFunction() {
  4.         // 函数体
  5.     }
  6. }
复制代码
在这个例子中,hiddenVariable和hiddenFunction只能在当前源文件内部访问。
C++的输入和输出

C++标准库中的全部标准函数和对象都放在名为std的命名空间中,这是为了防止它们与程序中界说的标识符产生冲突。比方,使用std::cout和std::endl来输出到控制台。
c++的Hello world

  1. #include<iostream>
  2. // std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
  3. using namespace std;
  4. int main()
  5. {
  6.     cout<<"Hello world!!!"<<endl;
  7.     return 0;
  8. }
复制代码
阐明:



    • 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
      以及按命名空间使用方法使用std。


    • cout和cin是全局的流对象,endl是特别的C++符号,表示换行输出,他们都包含在包含<
      iostream >头文件中。


    • <<是流插入运算符,>>是流提取运算符。


    • 使用C++输入输出更方便,不必要像printf/scanf输入输出时那样,必要手动控制格式。
      C++的输入输出可以自动辨认变量范例。

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5.    int a;
  6.    double b;
  7.    char c;
  8.      
  9.    // 可以自动识别变量的类型
  10.    cin>>a;
  11.    cin>>b>>c;
  12.      
  13.    cout<<a<<endl;
  14.    cout<<b<<" "<<c<<endl;
  15.    return 0;
  16. }
复制代码
std命名空间的使用惯例

std是C++标准库的命名空间,怎样展开std使用更合理呢?

  • 在一样平常练习中,发起直接using namespace std即可,如许就很方便。
  • using namespace std展开,标准库就全部暴露出来了,如果我们界说跟库重名的范例/对象/函数,就存在冲突题目。该题目在一样平常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以发起在项目开发中使用,像std::cout如许使用时指定命名空间 + using std::cout展开常用的库对象/范例等方式。
缺省参数

缺省参数是函数界说时的一个特性,它答应在函数的声明或界说中为某些参数指定默认值。如果没有为这些参数传递实参,函数就会使用这些默认值;如果传递了实参,则使用传递的值。
缺省参数的界说

当你界说或声明一个函数时,你可以为参数指定一个默认值,如下所示:
  1. void Print(int number = 0) {
  2.     cout << number;
  3. }
复制代码
在这个例子中,函数Print有一个参数number,它的默认值是0。这意味着如果你调用Print()而没有任何实参,函数将使用默认值0。
缺省参数的使用

调用函数时不传递参数

如果你在调用Print函数时不提供任何参数,它将使用参数的默认值:
  1. Print(); // 输出: 0
复制代码
调用函数时传递参数

如果你提供了参数,函数将使用你传递的值而不是默认值:
  1. Print(5); // 输出: 5
复制代码
缺省参数的规则


  • 默认值的位置:在函数原型或界说中,默认值必须位于参数列表的末端。也就是说,你必须从右向左指定参数的默认值。
  • 全缺省参数:全部参数都可以有默认值,这种函数调用时可以不提供任何实参。
  • 半缺省参数:只有部门参数有默认值。当你指定了某个参数的默认值时,全部位于其右侧的参数也必须有默认值。
  • 默认参数的次序:你不能为一个参数指定默认值,然后跳过前面的参数为后面的参数指定默认值。必须从右至左连续指定。
示例

下面是一个包含半缺省参数的函数示例:
  1. void Print(int number, int count = 1) {
  2.     for (int i = 0; i < count; i++) {
  3.         cout << number << " ";
  4.     }
  5.     cout << endl;
  6. }
  7. Print(5);        // 输出: 5 (使用了number的默认值,count的默认值)
  8. Print(5, 3);     // 输出: 5 5 5 (使用了传递的number值和count值)
复制代码
在这个例子中,Print函数的第一个参数number没有默认值,第二个参数count有默认值1。所以,如果你只提供一个参数,那么第二个参数将使用默认值1。
函数重载

函数重载是一种答应多个同名函数在类似的作用域中存在,只要它们的参数列表差异(即参数的个数、范例或次序差异)的特性。函数重载使得程序设计更加灵活,能够根据差异的参数执行相似或相关的任务。
函数重载的概念

当你在同一作用域内界说多个同名函数时,这些函数如果参数列表差异,它们就是重载的。重载的函数可以具有差异的参数数量、差异的参数范例,或者参数范例次序差异。然而,函数重载与函数返回范例无关,即不能仅通过返回范例来重载函数。
函数重载的规则


  • 参数列表必须差异:重载的函数必须有区别于其他同名函数的参数列表。
  • 返回范例不影响重载:纵然函数的返回范例差异,也不构成有用的重载。
  • 作用域的限定:函数重载只限于同一作用域内。在差异的作用域(如差异的命名空间或类中),纵然是完全类似的函数名和参数列表,也被视为差异的函数。
函数重载的示例

以下是一个展示函数重载的简朴示例:
  1. #include <iostream>
  2. using namespace std;
  3. // 重载函数:接受一个整数参数
  4. void display(int number) {
  5.     cout << "Displaying int: " << number << endl;
  6. }
  7. // 重载函数:接受浮点参数
  8. void display(float number) {
  9.     cout << "Displaying float: " << number << endl;
  10. }
  11. // 重载函数:接受两个整数参数
  12. void display(int number1, int number2) {
  13.     cout << "Displaying two int: " << number1 << " and " << number2 << endl;
  14. }
  15. int main() {
  16.     display(12);        // 调用第一个重载版本的display函数
  17.     display(12.3f);     // 调用第二个重载版本的display函数
  18.     display(12, 24);    // 调用第三个重载版本的display函数
  19.     return 0;
  20. }
复制代码
在这个例子中,我们界说了三个display函数。第一个接受一个整数参数,第二个接受一个浮点参数,第三个接受两个整数参数。由于它们的参数列表差异,这三个函数是重载的。
函数重载的工作原理

编译器通过函数的名称修饰(name mangling)来区分差异的载函数。它修改函数的名称,通常添加额外的信息以反映参数范例和参数数量,从而天生差异的函数名称以供链接器使用。
函数重载的注意点



  • 不能通过返回范例来区分重载函数。
  • 如果新的重载函数参数列表是现有函数参数列表的超集,这可能导致函数名称修饰出现题目,并可能引起函数调用的歧义。
    -重载函数时,要注意不要造成函数名称的混淆,否则编译器可能无法正确地选择调用哪一个函数。
引用

当然可以。在C++中,引用(reference)是一个非常便利的特性,它答应程序员为变量的别名。通过使用引用,我们可以通过这个别名来直接访问或修改变量的值。引用在很多环境下可以用来取代指针,因为它们提供了一种更安全和更易于理解的语法。
引用的界说和声明

引用的声明与指针类似,但它不必要使用星号*。引用在声明时必须被初始化,一旦初始化之后,它就不能再绑定到另一个变量上。
  1. 类型 &引用名 = 变量名;
复制代码
比方:
  1. int a = 10;
  2. int &ref = a; // 声明引用ref,并将其初始化为变量a的引用
复制代码
在这个例子中,ref是a的引用,它们代表同一个存储位置。
引用的特性


  • 引用是别名:引用实际上是原变量的别名,任何对引用的操纵都直接反映在原变量上。
  • 初始化时绑定:引用必须在声明时绑定到具体的变量,且一旦绑定就不能再改变引用所指向的变量。
  • 没有独立的内存地址:引用没有自己的内存地址,它共享原变量的内存地址。
  • 无需解引用:使用引用时不必要像指针那样进行解引用操纵,直接使用引用名即可。
引用的使用

传递引用到函数

引用经常用于函数参数,答应函数直接修改传入的参数值,而不是参数的副本:
  1. void addOne(int &num) {
  2.     num = num + 1; // 直接修改传入的参数
  3. }
  4. int main() {
  5.     int x = 5;
  6.     addOne(x); // x的值将变为6
  7.     return 0;
  8. }
复制代码
在这个例子中,addOne函数接受一个整数的引用作为参数,所以它可以直接修改x的值。
返回引用

函数也可以返回引用,如许返回的是变量的引用而不是副本:
  1. int &getFirstElement(int arr[]) {
  2.     return arr[0]; // 返回第一个元素的引用
  3. }
  4. int main() {
  5.     int myArray[] = {10, 20, 30};
  6.     int &first = getFirstElement(myArray); // first是myArray[0]的引用
  7.     first = 100; // 直接修改myArray[0]的值
  8.     return 0;
  9. }
复制代码
在这个例子中,getFirstElement函数返回数组第一个元素的引用,因此通过first可以直接修改myArray[0]的值。
引用的注意事项



  • 不能有null引用:指针可以被赋予nullptr,但引用必须指向一个有用的变量。
  • 不能重新绑定:一旦引用被初始化为一个变量,它就不能再指向另一个变量。
  • 引用不能指向数组:你不能创建一个数组的引用,但可以创建指向数组元素的引用。
引用和指针的差异点:


  • 引用概念上界说一个变量的别名,指针存储一个变量地址。
  • 引用在界说时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
    一个同范例实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中寄义差异:引用结果为引用范例的大小,但指针始终是地址空间所占字节个数(32
    位平台下占4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个范例的大小
  • 有多级指针,但是没有多级引用
  • 访问实体方式差异,指针必要显式解引用,引用编译器自己处置惩罚
  • 引用比指针使用起来相对更安全
内联函数

内联函数是一种优化本领,其目标是淘汰函数调用的开销。当函数体较小且被频繁调用时,函数调用的本钱可能会对性能产生负面影响。为了淘汰这种开销,可以将函数声明为内联函数,使得每次函数调用时,编译器将函数的代码直接插入到调用点,而不是通过跳转到函数代码的地址去执行。
内联函数的界说

内联函数通过在函数声明或界说之前添加inline关键字来指定。比方:
  1. inline int add(int a, int b) {
  2.     return a + b;
  3. }
复制代码
内联函数的特点


  • 淘汰调用开销:由于函数体直接插入到调用点,省去了函数调用的参数传递、返回值处置惩罚以及堆栈操纵等开销。
  • 无额外内存分配:内联函数不会像普通函数那样在栈上为局部变量分配内存。
  • 编译器优化:编译器可能会对内联函数的代码进行额外的优化。
内联函数的使用

内联函数通常用于以下场景:


  • 小型函数:函数体非常短小,比方简朴的算术运算或访问器函数。
  • 频繁调用的函数:如果一个函数在程序中频繁调用,那么将其声明为内联可能会提拔性能。
  • 性能关键代码:在性能敏感的代码路径中,使用内联函数可以淘汰函数调用开销。
内联函数的注意事项


  • 编译器选择:纵然函数被声明为内联,编译器也有权决定是否真正内联该函数。这取决于编译器的优化计谋和函数的复杂性。
  • 过度内联:如果过度使用内联函数,可能会导致代码膨胀,增加程序的内存占用,而且可能影响缓存效率。
  • 递归函数:内联递归函数可能会导致代码无穷增长,因此通常不推荐对递归函数使用内联。
  • 调试困难:内联函数可能会使得调试变得复杂,因为函数调用点没有明显的调用栈帧。
内联函数与宏的区别

虽然内联函数和宏都可以在编译时插入代码,但它们有一些重要区别:


  • 范例安全:内联函数是范例安全的,而宏不是。宏只是简朴的文本更换,可能会导致范例安全题目。
  • 作用域:内联函数可以访问局部变量和全局变量,而宏则不能。
  • 调试:内联函数可以像普通函数一样调试,宏则不能。
  • 参数的副作用:宏在展开时可能会对参数产生副作用,而内联函数则不会。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

科技颠覆者

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表