zoukankan      html  css  js  c++  java
  • 【C++ 系列笔记】01 C++ 与 C

    C++ 与 C

    Hello world!

    #include <iostream>
    using namespace std;
    int main() {
        cout << "Hello world!" << endl;
        system("pause");
        return EXIT_SUCCESS;
    }
    

    命名空间(作用域)

    • 双冒号::作用域运算符{$namespace}::

      • 如果不写 namespace 则使用全局命名空间

        ::function(params);
        
    • 命名空间:定义在全局命名空间下

      namespace {$namespace}{
      	// ...函数 类 结构体 变量...
      }
      
    • 命名空间可嵌套

      namespace {$namespace}{
      	// ...函数 类 结构体 变量...
          namespace {$namespace}{
      	// ...函数 类 结构体 变量...
      	}
      }
      
    • 多处同样的命名空间会累加而不会覆盖

      namespace {$namespace}{
          int a;
          // ...
      }
      namespace {$namespace}{
          int b;
          // ...
      }
      // a b 均在 {$namespace} 中
      
    • 无名命名空间仅在当前文件中可用

      namespace {
          int a;
          // 相当于 static int a;
          // ...
      }
      
    • 命名空间的别名

      namespace anotherName = {$namespace};
      

    C → C++ 异同

    • 变量检测

      • c success cpp failure
      int a;
      int a = 1;
      // c success 
      // cpp failure
      
      • cpp success
      int a = 1;
      // cpp success
      
    • 函数检测

      • c success cpp failure
      int function(p){// 形参类型
          // 返回值
      }
      // c success 
      // cpp failure
      
      • cpp success
      int function(int p){// 形参类型
          return 0;// 返回值
      }
      // cpp success
      
    • 函数调用检测

      • c success cpp failure
      int function(p){
          
      }
      int main(){
      	function(1, 2, 3);// 参数数量
      }
      // c success 
      // cpp failure
      
      • cpp success
      int function(int p){
          return 0;
      }
      int main(){
      	function(1, 2);// 参数数量
      }
      // cpp success
      
    • 类型转换

      • c success cpp failure
      char* p = malloc(4);// 隐式转换
      // c success 
      // cpp failure
      
      • cpp success
      char* p = (char*) malloc(4);// 隐式转换
      // cpp success
      
    • 结构体

      • c failure cpp success
      struct Type{
      	void method();
      }
      // c failure 
      // cpp success
      
    • 三目运算符

      • c failure cpp success
      int a = 1, b = 2;
      (a > b ? a : b) = 3; 
      // C 报错,认为 = 左边不是一个左值
      // C 的三目返回一个值,而 C++ 返回引用
      
      • c success
      *(a > b ? &a : &b) = 3; 
      
    • const 常量

      • C 的 const 是伪常量,C++ 不是

        const int a = 1;
        int* p = (int*)&a;
        *p = 2;
        // C 伪常量,可以修改,但在全局作用域声明的常量不可修改
        
        • c

          *p = 2 // p 指向 a

          a = 2

        • cpp

          *p = 2 // p 指向 a 的一个拷贝

          a = 1

        • 本质上来说,只要分配了内存,都可以通过指针去改。

          而 C++ 对 const 变量(大部分情况下)通过一个 hash 表存取。

          在自定义数据类型中或通过变量初始化 const 变量都会分配内存,可以直接修改。

      • ‘C 默认认为 const 为外部变量,C++ 不会

    引用

    • 返回引用的函数(表达式)可以作为左值(容易忽略的一种用法)

    • 引用的本质是一个指针常量int* const var,在底层实现(汇编)中与直接使用指针几乎没有任何区别

    • 对数组的引用

      int arr[10] = {...};
      int (&arrRef)[10] = arr;
      // 注意 int& arrRef[10] 是引用的数组,即存放引用的数组
      
    • const int &ref = 10常量引用(主要用于修饰形参)

      const int &ref = 10;
      

      底层实现大概是这样的,分配了内存,可以通过指针修改

      int temp = 10;
      int* const ref = temp;
      
    • C++11 的右值引用

      int&& a = 10;
      

      一定是一个右值,但允许修改

    内联函数

    用来代替 C 的宏

    • 宏的缺陷

      • 可读性

      • 无类型

      • 实现基于字符替换,无逻辑性

        #define Max(a, n) ((a) < (b) ? (a) : (b)
        int main(){
            int a = 10;
        	Max(++a, 11);
            // 展开为 ((++a) < (11) ? (++a) : (11)
            // 很明显与预期不符
        }
        
    • 内联函数

      inline void function(){
      	// 实现
      }
      

      内联函数实际上是代码片段,调用内联函数实际上是直接运行代码片段。

      省下了函数调用的开销。

      • 以下情况会导致编译器不认为这是一个内联函数(即使你加了 inline 关键字)
        • 存在循环
        • 存在过多的条件判断
        • 函数体庞大
        • 对内联函数进行取址(内联函数没有入口)
    • 类内定义的成员函数默认是内联函数

    函数的默认参数

    void function(int param1 = 1, string param2 = "2"){
    	// 实现
    }
    int main(){
    	function();
    }
    
    • 如果函数声明存在默认参数,则函数定义(实现)必须没有

      即函数声明和定义中仅允许一处存在默认参数

    函数的占位参数

    void function(int){
    	// 实现
    }
    

    主要用来重载 ++,作为占位参数重载函数。

    函数重载

    • 重载函数必须在同一个作用域

    • 区分重载函数的条件

      • 参数列表(类型、个数和顺序)
      • 注意存在默认参数时的二义性
    • C++ 符号的 C 链接性

      C++ 调用 以 C 的方式编译的 C 程序 就会出现链接不到函数的情况。

      这是 C++ 的多态性导致的,这使得 C++ 在函数名方面 与 C 存在不同的底层实现方式。

      解决方法

      • extern "C"告诉编译器以 C 的方式编译这个 C++ 函数(即不做 C++ 的多态性底层处理),以保证 C++ 调用的 C 链接性。

        extern "C" void function();
        
      • 或者直接在 C 的头文件中全部包含extern "C" {}

        // 在 C 函数的头文件中
        #ifdef __cplusplus
        exteern "C"{
        #endif
        
        // 函数声明
        
        #ifdef __cplusplus
        }
        #endif
        

        还存在一个问题:

        C++ 直接调 C 函数,VC++ 编译出错,g++ 编译没问题。

        猜测 g++ 偷偷做了优化。

  • 相关阅读:
    Go语言:如何解决读取不到相对路径配置文件问题
    Go组件学习:如何读取ini配置文件
    PMP学习笔记(一)
    SpringBoot安装与配置
    Homebrew中国镜像安装与配置
    Nginx日志常见时间变量解析
    openresty如何完美替换nginx
    Golang防止多个进程重复执行
    Windows 10 中CPU虚拟化已开启,但是docker无法运行
    彻底理解Python多线程中的setDaemon与join【配有GIF示意】
  • 原文地址:https://www.cnblogs.com/gaolihai/p/13149748.html
Copyright © 2011-2022 走看看