C++基础知识面试必备、复习细节 (8)(tuple、随机数、异常处理、多继承)

C++基础知识面试必备、复习细节 (8)(tuple、随机数、异常处理、多继承)

tuple类型
  • tuple是一个类似于pair的模板,pair类型是每个成员变量各自可以是任意类型,但是只能有两个成员,而tuple与pair不同的是它可以有任意数量的成员

  • 个人常把tuple当作一个结构体使用,如果只是一次使用的话就避免了结构体繁琐的创建

  • tuple的基本操作:

    tuple<int,string,int> t{1,"James",1000}; //可以用来存一个序号,名字,工资这样的信息
    auto t=make_tuple("1","James","12345678911");  //存序号,名字,电话 用auto可以自动判断
    auto name=get<1>(t); //返回名字  通过get<i>(tuple)返回第i-1个成员对象
    get<2>(t)="98765432111";  //get<>()返回的是引用,因此可以修改
    
  • 两个tuple相等当且仅当元素数量相同且每个元素相等,< 也是同理

  • 通过使用tuple可以令一个函数中返回多个值, 有时候可以令程序更简洁方便

随机数
  • 头文件: random

  • c++的随机数通过两部分解决随机数问题:随机数引擎类和随机数分布类

    随机数引擎类生成随机的unsigned整数序列,随机数分布类使用引擎返回特定概率分布的随机数

  • 常用的默认随机数引擎生成随机数:

       default_random_engine e;
        for (int i = 0; i < 10;i++)
            cout << e() << ' ';
    /* 16807 282475249 1622650073 984943658 1144108930 470211272 101027544 1457850878 1458777923 2007237709 */
    
  • 使用分布类型的对象得到指定范围的随机数

        uniform_int_distribution<unsigned> u(0, 9);  //生成0-9的随机数
        default_random_engine e;
        for (int i = 0; i < 10; i++)
            cout << u(e) << ' ';
    //0 1 7 4 5 2 0 6 6 9
    
  • 一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将其(包括引擎和分布对象)定义为static的,否则每次调用生成相同的序列。

  • 生成正态分布序列

        default_random_engine e;
        normal_distribution<> n(4, 1.5); //均值为4,标准差为1.5的正态分布
        for (int i = 0; i < 10; i++)
            cout << n(e) << ' ';
    //3.81705 2.36977 5.02643 2.38722 4.0499 5.11725 4.05041 3.21004 4.6938 4.30105
    
  • 生成伯努利分布序列(true or false 可以制定概率)

       default_random_engine e;
        bernoulli_distribution n(0.9); //伯努利实验的p=0.9
        for (int i = 0; i < 10; i++)
            cout << n(e) << ' ';
    //1 1 1 1 0 1 1 1 1 1
    
IO库
  • 八进制十六进制十进制

        cout<<hex<<20<<endl;  //14             将cout输出的整数转换为16进制
        cout<<oct<<10<<endl;  //12 			   将cout输出的整数转换为8进制
        cout << dec << 10<<endl;//10         将cout输出的整数转换为10进制
        cout<<0x20<<endl;   //0x开头表示十六进制  32
        cout << 010 << endl;  //0开头表示八进制   8
    
  • 浮点数输出格式

    	//制定打印精度
        double t = 3.1415926;
        cout.precision(3); //浮点数精度为3
        cout << t << endl;  //3.14
        cout.precision(5);
        cout <<t << endl;  //3.1416
    
异常处理
  • 执行throw时,跟在throw后面的语句将不再执行,程序的控制权从throw转移到catch块。因此,尽量不要在析构函数中写异常处理,避免内存泄漏。

  • 栈展开:对于抛出异常的函数的调用语句位于一个try语句块内,则检查与该try块关联的catch语句。如果找到了匹配的catch,则用该catch处理异常,否则如果该try语句嵌套在其他try块中,则继续检查与外层try匹配的catch语句,如果还没找到则退出当前的主调函数,继续在调用了这个函数的其他函数中寻找。

    栈展开过程也就是沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch子句为止,或者一直没找到,退出主函数后终止查找过程。

  • 一个异常没被捕获,则将终止程序

  • 构造函数中抛出异常,会导致析构函数不能被调用,但对象本身已申请到的内存资源会被系统释放

因为析构函数不能被调用,所以可能会造成内存泄露或系统资源未被释放

构造函数中可以抛出异常,但必须保证在构造函数抛出异常之前,把系统资源释放掉,防止内存泄露

  • 不要在析构函数中抛出异常

    如果某个操作可能会抛出异常,class应提供一个普通函数(而非析构函数),来执行该操作

    如果析构函数中异常非抛不可,那就用try catch来将异常吞下,不要让异常逃离析构函数

  •    try
        {
            //something
        }
        catch (exception &e)
        {
            cout << "Standard exception: " << e.what() << endl;
        }
    
多继承
  • 如果从多个基类中继承了相同的构造函数,则该类必须定义自己的构造函数
  • 当一个类拥有多个基类时,可能出现派生类从两个或多个基类中继承了同名成员的情况,则需要用前缀限定符访问该函数,否则会有二义性
  • 虚继承:令某个类做出声明,使其共享基类。在这样的情况下,虚基类被多次继承,也只有一个共享的基类 virtual public A
  • 虚派生只影响从指定了虚基类的派生类中进一步派生出的类,它不会影响派生类本身
  • 虚基类总是先于非虚基类构造,与它们在继承体系中的次序和为止无关
  • 多继承的父类的构造顺序,只与继承的顺序有关,与成员初始化列表顺序无关
  • 多继承的构造函数的顺序:
    • 虚基类的构造函数按照它们被继承的顺序构造
    • 非虚基类的构造函数按照它们被继承的顺序构造;
    • 成员对象的构造函数按照它们声明的顺序调用
    • 类自己的构造函数
  • 析构函数调用顺序与构造函数相反
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章