c++ primer c++11 不能不知道的基础知识点哦 01-02

23 篇文章 0 订阅
9 篇文章 0 订阅
本文介绍了C++11的基础知识点,包括.IO对象(cin, cout, cerr, clog)及其缓冲机制,标准库命名空间std,文件结束符与输入错误处理。此外,还讲解了基本数据类型、引用、指针的区别以及常量引用和指针。同时提到了预处理器宏和类型的别名定义。" 108343103,7788618,Android ViewPager+Fragment 数据源更新导致空白界面解决方案,"['Android开发', 'UI设计', '数据刷新', 'Fragment管理']
摘要由CSDN通过智能技术生成

01

  • 通常返回0表示好结果

  • 后缀 .cc .cxx .cpp .cp .C

  • 四个IO对象 cin cout cerr clog

  • #include <标准库头文件>
    #include “自定义头文件”

  • 操纵符 endl 效果
    结束当前行 并将于设备关联的缓冲区中的内容刷新到设备中
    刷新缓冲器的操作可以保证将目前为止程序所产生的所有输出都真正写入到输入流中
    而不仅仅是停留在内存中等待写入流

  • 标准库定义的所有名字都在std的命名空间中

  • 作用域运算符::

  • while(std::cin >> value)
    表达式 std::cin >> value 的返回值是 std::cin
    所以检查的是std::cin的状态
    遇到文件结束符(CTRL+D(UNIX), CTRL+Z(WINDOWS))或者输入错误时 istream 对象的状态会变成假

  • 后缀 .h .H .hpp .hxx

  • 一般默认情况下 cin 会刷新 cout 程序非正常终止也会刷新 cout
    cerr 默认是不缓冲的
    clog 默认是缓冲的

  • 在调试添加打印语句时 需要保证一直刷新流
    否则程序崩溃 可能导致 输出可能停留在缓冲区中
    从而导致关于程序崩溃位置的错误推断


02

  • 基本数据类型

    • 空类型
    • 算术类型
      • 浮点型
      • 整型
        • 整型数
        • 字符
        • 布尔值
  • 各类型最小尺寸要求见P30

  • 一般来说 float 和 double 分别具有 7 和 16 个有效位

  • char是有符号还是无符号决定于编译器

  • 赋给无符号一个超出范围表示的值 是对无符号表示的总数取模后的余数

    #include <iostream>
    using namespace std;
    
    int main()
    {
        uint8_t v = -1;
        cout << int(v) << flush;
        return 0;
    }
    
    输出是255 直接输出v是输出不了的 因为实际uint8_ttypedef unsigned char
    
  • 赋给带符号一个超时范围表示的值 结果未定义

  • 在一个表达式中 既有无符号数又有有符号数时 会自动将有符号的提升转换为无符号的 将会导致如上一点的不可预知行为

  • 内置类型列表初始化时如果存在信息丢失的风险编译器将报错

    int i{291.2};
    
    error: narrowing conversion of '2.9119999999999999e+2' from 'double' to 'int' inside 
    { } [-Wnarrowing]
    
  • extern 声明

  • 初始化是创建时赋予初始值 赋值是擦除当前值赋予新值

  • 初始化方式

    int a = 0;
    int b = {0};
    int c{0};
    int d(0);
    
  • 多行书写字符串字面值

    cout << "hello "
            "world!"
         << endl;
    
  • 默认初始化 以下针对 内置类型 内置类型 内置类型 进行说明 P40
    如果内置类型未被显示初始化 其值由位置决定
    定义于任何函数体之外的变量被初始化为0
    定义于函数体内部的内置变量将不被初始化(静态局部变量例外 执行 值初始化)

  • 自定义标识符

    • 不能连续两个下划线
    • 不能下划线紧连大写字
    • 定义在函数体外的标识符不能以下划线开头
  • 引用引用类型与绑定对象类型需要严格匹配 两种例外 1 const 2 多态

    • 引用只能绑定在对象上
    • 引用本身不是一个对象 不能定义引用的引用
    • 引用不能与字面值或者表达式的计算结果绑定在一起
  • 指针的值指针的类型与所指向的对象需要严格匹配 两种例外 1 const 2 多态

    • 指向一个对象
    • 指向紧邻对象所占空间的下一个位置 比如尾指针
    • 空指针 nullptr
    • 无效指针 野指针
    • 引用不是对象 所以无法定义指向引用的指针
  • 指针都建议初始化 未初始化的指针或野指针会引发无法预料的后果

  • 指针与引用区别 引用必须初始绑定 一旦绑定无法绑定到其他对象 而指针则无此限制

  • 类型相同的合法指针 使用 == 或者 != 进行比较时 相等的几种情况

    • 都为空
    • 指向同一对象
    • 都指向统一对象的下一地址 比如尾指针
    • 一个指针指向对象的下一个地址 另一个指针指向另一个对象
  • void*指针

    • 比较
    • 作为函数输入输出
    • 赋值给另一个void*指针
    • 不能直接操作void*指针指向的对象 因为不知道是啥
  • 默认状态下 const 对象仅在文件内有效 详见P54 多个文件共享const可以使用 extern const

    // test.cpp
    const int x = 1;
    const int *p1 = &x;
    
    //main.cpp
    #include <iostream>
    using namespace std;
    
    const int x = 2;
    const int *p2 = &x;
    
    int main()
    {
        cout << "hello world!" << endl; // 在这里打上断点 然后debug观察 p1 p2 *p1 *p2 就可以验证
    }
    

    在这里插入图片描述

  • 对常量的引用称为常量引用(reference to const)

    • 允许常量引用绑定 非常量 的对象 字面值 甚至是一个一般表达式
      类似于ri绑定了一个临时变量 因为const是不允许改的 所以这样合法
      如果去掉ri的const 那么改ri类似改一个临时变量 所以就把这种行为归为非法
    double dval = 4.14;
    const int &ri = dval;
    
    // 相当于如下
    const int temp = dval;
    const int &ri = temp;
    
  • 指向常量的指针 (pointer to const) 指针常量

  • 常量指针(const pointer) 指针本身是常量

  • 顶层const 表示指针本身是常量

  • 底层const 表示指向的对象是一个常量 引用是指向性质的 常量引用是底层指针

  • 将变量声明为 constexpr 可以由编译器来验证变量的值是否是一个常量表达式

  • 常量表达式

    • 不会改变
    • 编译时期就可以得到计算结果的表达式
      需要在运行时才可以计算得到 sz 的值 不是常量表达式
      const int sz = getsize()
      
    • 可以看出 使用constexpr的值必须编译时已知 但是cosnt的不需要
  • 目前为止接触到的字面值类型

    • 算术类型
    • 引用
    • 指针
  • constexpr修饰指针时 一定是修饰的指针本身而不是指针指向的对象P59
    constexpr指针的值受到严格限制 nullptr 或者 0 或者固定地址的对象
    所有函数体之外定义的变量
    静态局部对象

  • 别名

    • typedef double wages; wages 是 double 的别名
    • typedef wages base, *p; base 是 double 的别名 p 是 double* 的别名;
    • using SI = Sales_Item; SI 是 Sales_Item 的别名
    • typedef char *pstring;
    • pstring 是一个指针
    • pstring 是一个指向char的指针
    • const pstring cstr;
    • sctr 是一个常量pstring
    • cstr 是一个常量([指向char的]指针)
    • cstr 是一个常量指针
    • const pstring *ps;
    • 上面已经得到 const pstring 常量([指向char的]指针)
    • ps 是一个指针 他的对象是指向char的常量指针
  • auto 自动推导类型

    • auto 一般会忽略顶层const 底层const会保留P62
    • 希望保留顶层const 需要显示 const auto
    • auto x = 一个引用 auto对引用所绑定的对象进行推导
      const int ci = 0;
      &cr = ci;
      auto b = cr;
      其实是对ci进行推导 然后忽略顶层const 然后b是一个普通整型
      
  • decltype类型指示符 decltype需要参考左值右值相关内容
    分析表达式得到他的类型 确不计算他的值 decltype(f()) sum = x;

    • 如果decltype使用的表达式是一个变量 则返回该变量的类型
      (包括顶层const和引用在内 引用从来都作为其所指对象的同义词出现 只有在decltype这里例外了)

    • 如果decltype使用的表达式不是一个变量 则返回表达式结果的类型
      有些表达式向decltype返回一个引用 一般情况下意味着该表达式的结果对象能作为赋值语句的左值

    • 如果decltype的是一个加了括号的变量 即如下
      decltype(variable) 常规的
      decltype((variable)) 这里的双层括号
      那么其实decltype使用的表达式不是一个变量了 而是(variable)这样一个表达式
      然后variable变量是一种可以作为赋值语句左值的特殊表达式
      然后这是一个左值 然后这样的结果就会是一个引用类型
      结论
      decltype((variable))的结果永远是引用
      decltype(variable)只有在variable本身是引用时结果才是引用

      int test_decltype()
      {
          int i = 42;
          int *p = &i;
          int &r = i;
          // 错误 a 是一个引用 未初始化报错
          decltype(r) a;
          // 正确 表达式的结果是一个具体的int值 而非引用
          decltype(r + 0) b;
          // 错误 *p解引用得到的对象是一个左值可以给这个结果赋值 类型是int& 未初始化报错
          decltype(*p) c;
          // 错误
          decltype((i)) d;
          // 正确
          decltype(i) e;
      }
      
  • 类内初始值 创建对象时 类内初始值用于初始化数据成员 没有类内初始值的将默认初始化(内置类型就有可能未初始化出现错误哈哈哈)
    可以用以下的几种初始化方式进行类内初始值的设置 除了用()的方式

    struct test_struct
    	{
    	    int a = 2;
    	    int b{3};
    	    int c = {4};
    	    int d;
    	};
    
  • 预处理器

    • #define

    • #ifdef

    • #ifndef

    • #endif

    • #pragma once

    • 预处理器 在C++编译过程中执行的一段程序

    • 预处理器变量 由预处理器管理的变量(命名空间不在std中)
      在程序编译之前预处理器负责将程序中的预处理器变量转换为真实值

////////////////////////////////////////////README//////////////////////////////////////////////////// // DebugLog--write some log for debug // //初衷: 版本开发的时候,有些功能点是可以项目无关的,比如是解析某个文件;开发完成之后,测试的话, // // 需要整改项目程序运行、测试,功能点的触发条件比较麻烦。所以,有的时候,对于这样的功能点, // // 我会选择进行本地开发,然后再合到项目中去. // // 但是,每次功能点开发的时候,一般用的是printf直接打屏,但是项目中用的是写文件,所以移植 // // 的时候还需要进行不少改动. // // 于是,我就想自己写个log,可以与项目的日志函数进行适配。那么,上面的问题可以得到比较好的 // // 解决(或者说是规避)。 // //附注:我不知道这样做有没有意义,也就是根据自己的经验,试着做了下。经验不足,水平有限,肯定会 // // 导致设计不足,不对,甚至是整个设计没有意义。如果是这样,希望能不吝交流、赐教. // // EMail: hu__haifeng@163.com // ////////////////////////////////////////////////////////////////////////////////////////////////////// //Version :0.5 // //Description:该版本打造了基本的架构,并且实现了不带参数的打印日志(仅仅是字符串),可以进行监督的测试.// // 由于我项目经验有限,仅仅见过两种不同的项目日志分隔,所以也只能以此为参考,不一定可以 // // 适配其他项目日志函数. // //Adapter :可以用宏定义来进行适配。比如: // // #ifdef __CLOG_H__ // // #define DEBUG(VAR) mylog.Print(__FILE__, __LINE__, VAR, LOG_DEBUG) // // #else // // #define DEBUG(VAR) function //项目用的标准的日志函数. // // #endif // // // //Plan :1.0版本写成可以带参数的日志。2.0版本实现客户端、服务器版本(可以支持不同的进程写日志)。// //////////////////////////////////////////////////////////////////////////////////////////////////////
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值