【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++ 偷偷做了优化。

posted @ 2020-06-04 18:52  高厉害  阅读(121)  评论(0编辑  收藏  举报