3、字符串、向量和数据

3.1 命名空间的using声明

  • 形式:using namespace::name;


3.2 标准库类型string

  • 表示可变长的字符序列

  • size()的返回值值类型是string::size_type,一个无符号的整数
  • string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符两侧对象至少一个时string,如:

    string s6 = s1 + ", " + “world”;//正确

    string s7 = “hello” + “,” +s1; //错误

  • 中定义了函数isalnum()、isdigit()…
  • 对string对象的每个元素做某个操作,如
    for (auto &c : s)    //基于范围的for语句
       c = toupper(c);   //改成大写
    
  • 使用下标方式迭代:
    for(decltype(s.size()) index=0;index!=s.size()
       &&!isspace(s[index]); ++index)
       s[index] = toupper(s[index]);
    
  • string 对象上的操作
    • 1.初始化对象的方式
    • 2.所能执行的操作:函数名调用操作、<<、+等运算符操作
      • string s;cin>>s1>>s2;: 会自动忽略开头的空白(\n \t)
      • while(getline(cin,s));:遇到换行符结束但不会存到s中,返回流参数

3.2 标准库类型vector

表示对象的集合,也叫容器,是一个类模板

#include
using std::vector

  • 编译器根据模板创建类或函数的过程称为实例化
  • 初始化如:
    vector<T> v5{a,b,c,d,...}
    vector<T> v5={a,b,c,d,..}  //注意这里不是圆括号
    

3.4 迭代器

  • 有效的迭代器或者指向某个元素、或者指向容器中尾元素的下一位置。
  • 有迭代器的类型同时拥有返回迭代器的成员,比如都有begin/cbegin()和end/cend()成员
    • *iter:返回迭代器所指元素的引用
    • iter->mem:解引用该元素,(*iter).mem
  • 迭代器类型:
    vector<int>::iterator it;  // it能读写vector的元素
    string::iterator it;  // it能读写string对象中的元素
    vector<int>::const_iterator it;  // it能读不能写vector的元素
    string::const_iterator it;  // it能读不能写string对象的元素
    
  • 谨记:但凡是使用了迭代器的循环体,都不要向迭代器所属的容器中添加元素
  • 迭代器的运算:iter±n表向前后移动n个元素,iter1-iter2表之间的距离(difference_type),
  • 例:
    auto beg = text.begin(),end = text.end();
    auto min = text.begin() + (end - beg)/2;
    while(mid != end && *mid != sought){
       if(sought < *mid) end = mid;
       else beg = mid+1;
       mid = beg + (end-beg)/2;
    }
    

3.5 数组

  • 复杂的数组声明
    • int *ptrs[10]; //ptrs是含有10个整型指针的数组
    • int &refs[10] = /* ? */ //错误,不存在引用的数组
    • int (*pArray)[10] = &arr; //指向含有10个整数的数组,从内向外理解
    • int (&arrRef)[10] = arr; //引用一个含10个整数的数组
    • int *(&array)[10] = ptrs; //array是数组的引用,该数组含有10个指针
  • 数组下标为定义在中的size_t类型
  • 数组与指针:
    int ia[]={0,1,2};
    auto ia2(ia);  //ia2是一个整型指针,指向ia的第一个元素
    decltype(ia) ia3 = {0,1,2};//ia3是数组
    int *beg=begin(ia);  //指向ia的首元素
    int *last=end(ia);   //指向ia尾元素的下一位置的指针
    
  • 与旧代码的接口:
    • 允许使用空字符结束的字符数组来初始化string对象或为string对象赋值
    • const char *str=s.c_str();//不能保证返回的数组一直有效
    • 数组初始化vector对象:
      int int_arr[]={0,1,2,3,4,5};
      vector<int> ivec(begin(int_arr),end(int_arr));
      

4.表达式

4.11 类型转换

  • 隐式类型转换
    • 表达式中,比int小的会提升为较大的整数类型
    • 条件中,非布尔会转换成布尔类型
    • 初始化过程中,初始值转换成变量类型
    • 算术转换:
      • 运算对象会转换成最宽的类型
      • 整数值会被转换成浮点类型
    • 整型提升
      • char、uchar、short、ushort会转int,不能存则转unsigned int
      • 较大的char(wchar_t、char16_t、char32_t)会转成int、uint、ulong、llong、ullong中最小的能容纳原类型值得一个
    • 无符号类型得运算对象
      • 先进行整型提升
      • 无符号>=带符号(类型大小),对象转为无符号
      • 无符号<带符号(类型大小),如 unsigned int a,long b,若a<=b,a转b,否则转a
  • 显示转换:
    • 形式:cast-name(expression)
      • type是目标
      • expression是要转换的值
      • case-name①static_case、②dynamic_case、③const_cast、④reinterpret_cast中的一种
        • ①.任何具有明确定义的类型转换
          double s=static_case<double>(j)/i;
          
        • ②.只能改变运算对象的底层const
          const char *pc;
          char *p=const_cast<char*>(pc);//正确但通过p写行为未定义
          
        • ③为运算对象的位模式提供较低层次上的重新解释
          int *ip;
          char *pc=reinterpret_cast<char*>(ip);//很危险
          string str(pc);//可能产生错误
          

4.12 运算符的优先级表

  • p148页

5.语句

5.6 TRY语句块和异常处理

异常:存在运行时的反常行为,超出了函数的正常功能范围,如失去数据库连接、遇到意外输入。—设计系统最难的一部分

  • throw表达式:用来表示遇到了无法处理的问题,我们说throw引发了异常
  • try语句块:用它处理异常,以try语句块开始,多个catch子句结束。我们称为异常处理代码。
  • 一套异常类:用于在throw和相关catch子句之间传递异常的具体信息
  • 例:
    #include 
    while(cin>>item1>>item2) {
       try{
          if(item1.isbn() != item2.isbn())
             throw runtime_error("Date must refer to same ISBN");
       } catch (runtime_error err) {
          // 提醒用户两个ISBN必须一致,询问是否重新输入
          cout<<err.what()
             <<"\nTry Again? Enter y or n"<<endl;
             char c;
             cin>>c;
             if(!cin || c == 'n') break;
       }
    }
    
  • 标准异常:
    • 定义了最通用的异常类,只报告异常发生
    • 定义了常用的异常类
    • 定义了bad_alloc异常类型
    • 定义了bad_cast异常类型

6.函数

  • 组成:return value、function name、parameter、
  • 名字有作用域,对象有生命周期

6.2.6 含有可变形参的函数

  • initializer_list 形参

    • 与vector不一样的是,initializer_list对象中的元素永远是常量值,无发改变
      void error_msg(ErrCode e,initializer_list<string> il){
         cout<<e.mesg()<<": ";
         for(auto beg=il.begin();beg!=il.end();++beg)
            cout<<*beg<<" ";
         cout<<endl;
      }
      //调用:
      error_msg(ErrCode(42),{"test1","test2"});
      
  • 省略符形参

    • 只能出现在形参列表的最后一个位置
    • 你的C编译文档会教你怎么使用varargs
  • 值是怎么返回的

    • 返回的值用于初始化调用点的一个临时变量,该临时变量就是函数调用的结果
    • 不要返回局部对象的引用或指针
  • 列表初始化返回值

    • C++ 11规定函数可以返回花括号包围的值的列表,如:
      vector<string> process(){
         return {"aa","bb"};
      }
      
  • 主函数main的返回值

    • 没有语句隐式返回0
    • 中定了两个预处理变量:EXIT_FAILUREEXIT_SUCCESS
  • 返回数组指针的函数:数组维度必须跟在函数名后,形参列表跟在函数名后且先于数组维度

    Type (*function(parameter_list))[dimension]
    int (*func(int i))[10];
    
  • 使用尾置返回类型

    尾置返回类型跟在形参列表后,->开头,原来的位置替换位auto,如:

    auto func(int i) -> int(*)[10];
    
  • 使用decltype,如:

    int odd[]={1,3,5};
    int even[]={0,2,4};
    decltype(odd) *arrPtr(int i){
       return (i%2)?&odd:&even;
    }
    

6.4 函数重载

同一作用域内几个函数名字相同但行参列表(类型或数量)不同,称为重载函数

  • 一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开
  • 如果形参是指针或引用,可通过区分其指向的是常量还是非常量实现函数重载,如:
    Record lookup(Account&);   //用做Account的引用
    Record lookup(const Account&); //新函数,作用于常量的引用
    

你可能感兴趣的:(C++基础)