c++随记

平常笔记

  1. 初始化数组需要定义大小才能被cin

  2. cinscanf一样,都跳过空格

  3. publicprivate:用于类的封装

  4. new malloc的主要区别:new调用构造函数,malloc不会

  5. int *p1 = new int[10],int *p2 = new int[10]()区别:p1申请的空间里的值是随机值,p2申请的空间里的值已经初始化

  6. 引用:

    1
    2
    3
    4
    int a=10;
    int &b=a;
    int c=20;
    b=c;//这个意思就是说,将c的值赋值给a,因为b是啊的别名

    本质为:

    1
    2
    3
    4
    5
    int a = 10;
    int* const b = &a;//所以在引用后,不能改变空间
    *b = 30;
    int c = 20;
    *b = c;
  7. 左值,右值:(但凡能去地址,就是一个左值)

    1
    2
    x++;//把x的值取出来,放进临时变量里面,再让临时变量++,此时x的值是临时变量的是,也就是右值
    ++x;//自增,然后把自己返回,也就是说是左值
    • 左值经过函数返回会变成右值,因为会发生拷贝

    • 函数里,定义的参数,是个左值

    • 用引用写交换函数

      1
      2
      3
      4
      5
      6
      void swap(int &a,int &b)
      {
      int tem =b;
      b=a;
      a=tem;
      }
    • int &a:左值引用

    • int &&a:右值引用

  8. 对输出小数的控制

    • 不引入头文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include<iostream>

    int main()
    {
    double e=1;
    cout.precision(4);
    cout<<fixed<<e/3<<endl;
    cout<<e/3<<endl;
    //将输出4位小数
    return 0;
    }
    • 引入头文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      #include<iostream>


      int main()
      {
      double e=1;
      cout<<fixed<<setprecision(4)<<e/3<<endl;
      //输出4位小数
      return 0;
      }
  9. string.at(n):用于获取指定字符,n就是获取字符的下标

  10. 使用new,创建的指针p,用法和数组一样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    int main()
    {
    int *p=new int[5];
    int *q=new int[5];
    for(int i=0;i<5;i++)
    {
    p[i]=i;//可以相当于创建了一个数组,对于数组的存储可以用arr[i]=int类型

    }
    for(int i=0;i<5;i++)
    {
    q[i]=p[i];
    }
    for(int i=0;i<5;i++)
    {
    cout<<q[i]<<"\t";
    }
    system("pause");
    return 0;
    }
  11. 打印16进制

    1
    cout<<hex<<"类容"<<endl;//可用于打印地址
  12. public成员最好不要在类中赋值,而是使用成员初始化列表

  13. 在使用继承释放内存时,注意父类使用虚析构

  14. 构造函数的技巧:在声明的时候参数缺省

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class My_class{
    public:
    My_class(double num1=0.0,double num2=0.0);
    ~My_class();
    private:
    double m_num1;
    double m_num2;

    };

    //构造
    My_class::My_class(double num1,double num2) {
    cout << "My_class::My_class() " << endl;
    }

    在声明的时候对参数缺省,在定义的时候不需要(会报错)

    image-20221210113213961

  15. 引用做函数返回值

    • 不要将局部变量作为返回值

    • 函数的返回值可以作为左值存在

    • 如果函数的返回值,是左值必须是引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17

      int& func()
      {
      //int a=10;//这么写会报错
      static
      return a;
      }


      int main()
      {
      int& a = func();
      cout << a << endl;
      cout << a << endl;
      system("pause");
      return 0;
      }
  16. 在c++里面,有时候打印不一定需要,string类,特可以用字符指针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    template <typename Type_1,typename Type_2>
    void Cout(Type_1 a=0,Type_2 b=0)
    {
    cout<<"a="<<a<<endl;
    cout<<"b="<<b<<endl;
    }


    int main()
    {
    Cout<char*,string>("char*","string");
    /* cout<<add<int,int>(a,b)<<endl;
    cout<<add<int>(a,b)<<endl;
    cout<<add<>(a,b)<<endl;*/
    system("pause");
    return 0;
    }

    运行结果:

    image-20221211212205234

  17. c++中读取字符串的函数

    • getline() string类

      运行结果:

      image-20221227225137590

    • cin.getline()

      1
      2
      3
      char str[100];
      cin.getline(str, 20, '\n')
      //cin.getline()里面三个参数,第一个是要储存的字符串数组,第二个是最大长度 + 1,最后一个位置用来存储'\0',也就是说你填20,但是只能存前19个字符,第三个是结束符,可省略,默认是换行符

      当第二个参数大于数组本身的长度时,只会读取数组这么长

  18. 使用指针遍历时,不能使用数组名,必须重新创建一个指针

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main()
    {
    int arr[6]={0},*P=arr;
    for(int i=0;i<6;i++)
    cin>>arr[i];
    for(int i=6;i>0;--i)
    {
    cout<<*P++;
    }
    }
  19. 字符串的输入

    • string类

      使用getline(cin,string名称)

    • 字符数组类

      使用cin.getline(str,sizeof(str));

  20. c++的强制类型转换方式

    使用static_cast<强制传换成的类型>(被转变量名)

    1
    2
    3
    int a =2;
    short b=3;
    b=static_cast<int>a;
  21. using的三个用处

    • 引入命名空间

    • 指定别名

      1
      using ModuleType = ClassOne;
    • 在子类中引入基类的成员

      1
      2
      using ClassType::ModuleType;

  22. noexcept关键字的使用

    1
    void ThreadEntry() noexcept;
  23. default是c++11的标准,它的作用是告诉编译器声明一个无参的默认构造函数

    • 与手动写的无参构造有什么区别
      • 多文件的编程中,使用default声明的不需要再写实现
      • 代码执行的效率很高
    1
    2
    3
    4
    5
    6
    7
    class test{

    public:
    test() = default;
    test(int a){}
    int add(){}
    };
  24. explict这个关键字的作用是用于修饰只有一个参数的构造函数,并要求为显示的,也就是防止用户做可能会发生隐式转换的事情,会报错

  25. noexcept这是c++11增加的函数,目的是为了提升函数效率,即告诉编译器这个函数不会产生异常。

  26. =delete表示不能被调用

  27. decltype

    auto根据=右边的初始值 value 推导出变量的类型,而 decltype 根据 exp 表达式推导出变量的类型,跟=右边的 value 没有关系。

  28. lambda表达式

    [见这个](lambda高级使用 - chg (tsy244.github.io))

  29. c++ 父类构造函数声明vitual的作用

    在C++中,当我们派生一个子类时,子类的构造函数会默认调用父类的构造函数以初始化父类的成员变量。而在某些情况下,我们希望能够在父类的构造函数中调用子类重写的虚函数,此时就需要在父类的构造函数声明为virtual

    具体来说,当父类的构造函数声明为virtual时,如果我们通过子类的指针或引用调用这个构造函数,那么实际被调用的将是子类的构造函数,而不是父类的构造函数。这样可以保证在父类中调用子类的虚函数时,已经完成了子类对象的初始化,避免出现未定义行为的情况。

    需要注意的是,对于同一对象,构造函数的调用顺序是按照继承层次由上至下的,也就是从基类到派生类。因此,在子类的构造函数中,父类的构造函数已经执行完毕,可以调用虚函数,无需再将父类的构造函数声明为virtual

  30. c++父类里使用vitual的函数子类还会继承嘛?

    在 C++ 中,如果一个父类声明了一个虚函数,那么子类继承这个虚函数并且在子类中可以进行重写(override)。当然,如果子类不想重写这个虚函数,也可以直接继承父类中的实现。

    需要注意的是,在父类的构造函数中调用虚函数时,子类的版本不会被调用。这是因为在子类的构造函数执行之前,父类的构造函数已经执行完毕了,此时子类还没有初始化完成。如果在父类的构造函数中调用子类的函数,就有可能出现未定义行为的情况,因此编译器会强制执行父类版本的虚函数。

    总之,如果一个虚函数在父类中已经声明,子类无论是否重写它,在概念上都是继承了这个虚函数,即子类对象拥有这个虚函数的 vtable(虚函数表) 和 vptr(虚指针),可以通过指针或引用来使用这个虚函数。

  31. 在使用多态的时候应该将父类的析构函数声明vitrual

  32. 在使用virtual的时候体积的增大,是因为携带了很多信息,如虚函数表,虚指针

  33. 纯虚函数

    1
    virtual void testFunc()=0;

    含有纯虚函数的class不能声明的对象,只能被派生

  34. 在初始化列表中调用父类的构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class son:public fat {
    public:
    son();

    ~son();
    };

    //构造
    son::son(): fat(1)
    {
    cout << "son::son()" << endl;
    }
  35. move()的使用

    于在不进行复制或赋值操作的情况下将对象的所有权从一个对象转移到另一个对象。通过使用move,可以避免对资源进行复制和销毁的昂贵开销,从而提高代码效率。

    在构造函数中可以使用

    1
    2
    3
    fat::fat(std::string str):str(std::move(str)) {
    cout << "name::name()" << endl;
    }
  36. final关键字的使用

    • 在类上面的使用

    类的声明中使用final关键字,可以指示该类不能被继承

    • 在虚函数上面的使用

      在虚函数的声明中使用final关键字,可以阻止子类对该虚函数进行覆盖

    需要注意的是,final关键字只能用于类或虚函数的声明中,而不能用于变量、函数或其它类型的声明中。

  37. constconstexpr

    • const 只是将变量标记为“只读”,并非编译期常量,而 constexpr 则需要在编译时求值,生成编译期常量。

      1
      2
      const int constInt=10;//只读
      constexpr int constNum=10;//编译期常量
    • 被声明为 constexpr 的变量或函数,必须要满足编译器的常量表达式要求,可以在编译时进行求值。

    • constexpr 变量应该使用特定的类型,如整数类型、枚举类型以及一些简单的浮点类型。

    • constexpr 函数具有与普通函数类似的语法,但是其参数和返回值类型也必须是可求值的。在调用 constexpr 函数时,所有参数必须是编译期常量。

  38. const修饰函数

    在C++中,const 关键字可以作用于成员函数、非成员函数、指针和引用等对象上。如果将 const 应用于成员函数,则该函数被视为只读函数(read-only function),即在该函数内不能修改成员变量的值,也不能调用非 const 成员函数。

    1
    2
    3
    4
    5
    void fat::test() const {
    //
    }


  39. constexpr修饰函数

    1. 函数必须是类的一部分;
    2. 函数有返回类型,而且返回类型必须为字面值类型;
    3. 函数体中只能包含诸如 returnstatic_asserttypedef 等语句,不能有分支语句(例如 ifwhile)和循环语句(例如 fordo-while);
    4. 函数的参数列表中只能有字面值类型、引用和指针,而且参数都必须是 constexpr 的;
    5. 将函数声明为 constexpr 时,函数体内的所有函数调用都必须是 constexpr 的,这也意味着被调用的函数必须是 constexpr 的。
    1
    2
    3
    constexpr void fat::test() {

    }
  40. void(*)(int,int)void(int,int)区别

    一个是函数指针,一个是函数

  41. 显示和隐式转换

    隐式转换和显示转换是类型转换中的两种方式,其中隐式转换是指在代码中转换类型时,不需要明确地指定要进行类型转换,而是根据上下文环境自动进行转换。相反地,显示转换则是指需要明确地在代码中使用强制类型转换的语法来将一种类型转换为另一种类型。

    隐式转换通常是由编译器自动完成的,它允许代码更简洁、更易读和更容易维护。例如,当一个整数值被分配给一个接收实数的变量时,编译器会自动将整数隐式转换为实数。

    与此相反,显示转换则需要在代码中使用强制类型转换的语法(例如“(int)x”)来明确告诉编译器我们要将某个值转换为另一种类型。在有些情况下,显示转换是非常必要的,例如当我们需要将浮点数转换为整数时,需要使用显示转换来避免数据精度丢失。

  42. 将c++的string转变为c的string

    使用string的c_str()函数

  43. 在C++中,可以使用std::reverse()函数来翻转一个序列中的元素。该函数定义在头文件中,其语法如下:

    1
    2
    	template <class BidirectionalIterator>
    void reverse (BidirectionalIterator first, BidirectionalIterator last);
  44. find()

    1
    auto it = find(vec.begin(), vec.end(), value);
  45. c++的可变列表

    注意头文件<cstdarg>

    va_listva_startva_argva_copyva_end(end是清楚之前的参数列表)等预定义宏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    	#include <cstdarg>

    using namespace std;

    auto func(int count,...)-> decltype(count){
    va_list args;
    va_start(args,count);
    int sum=0;
    for (int i = 0; i < count; ++i) {
    sum+= va_arg(args,int);
    }
    return sum;
    }


    int main(){
    cout<<func(5,1,2,3,4,5);
    return 0;
    }

    以下部分代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    	#include <iostream>
    #include <cstdarg>

    using namespace std;

    void print(const char* format, ...) {
    va_list args;
    va_start(args, format);

    while (*format != '\0') {
    if (*format == 'd') {
    int value = va_arg(args, int);
    cout << value << endl;
    }
    else if (*format == 'f') {
    double value = va_arg(args, double);
    cout << value << endl;
    }
    ++format;
    }

    va_end(args);
    }

    int main() {
    print("df", 123, 3.14);

    return 0;
    }

  46. 可变参数模板

    • 要么重载函数

      要么通过方法,在最后直接返回

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    	template<typename T>
    T func2(T value){
    return value;
    }


    template<typename T,typename ...Args>
    T func2(T value,Args...args){
    return value+ func2(args...);
    }

    int main(){
    cout<<func2(5,1,2.3,4.6,'1',true);
    return 0;
    }



  47. 使用auto接纳引用,我们需要手动添加&

  48. 部分现遇的STL算法函数

    1. 查找:find、find_if、find_end、find_first_of、adjacent_find、count、count_if
    2. 排序:sort、stable_sort、partial_sort、nth_element、make_heap、sort_heap
    3. 操作:copy、copy_n、move、swap、swap_ranges、transform、fill、generate、replace、remove、unique、reverse
    4. 数值:accumulate、inner_product、partial_sum、adjacent_difference、iota
    5. 集合操作:set_union、set_intersection、set_difference、merge、includes
    6. 通用算法:for_each、min、max、minmax、clamp、equal、lexicographical_compare、next_permutation、prev_permutation、rotate
  49. 关于48部分函数的解释

    • find()查找该值在容器中是否存在
    • count()计算容器中该value的数量
    • sort()对容器内的元素排序的函数
    • copy()对容器的拷贝
    • transform() 将原来容器的数据导入到现在这个容器当中
    • fill()它可以将一个容器中的所有元素设置为指定的值
    • generate()它可以使用指定的函数对象生成容器中的元素。它通常用于初始化容器或将容器重置为特定值
    • replace() replace函数是C++ STL中的一个函数,它可以将容器中的所有指定值替换为另一个值。它通常用于将容器中的特定元素替换为其他元素。
    • remove() 选择一个元素移到最后面
    • unique() 使得只有一个元素
    • reverse() 它可以将容器中的元素反转。它通常用于反转容器中的元素顺序。
    • iota() 它可以将指定的值序列填充到容器中。它通常用于初始化容器中的元素。
    • merge() 它可以将两个已排序的容器合并为一个已排序的容器。它通常用于对已排序的容器进行合并操作。
    • includes() 它可以判断一个容器是否包含另一个容器中的所有元素。它通常用于判断一个容器是否包含另一个容器。
    • for_each() 它可以对容器中的每个元素执行指定的操作。它通常用于对容器中的元素进行遍历操作。
    • rotate 它可以将容器中的元素旋转到指定的位置。它通常用于对容器中的元素进行旋转操作。
  50. namespace

    • 简绍

    • 可以嵌套 ,还用inline相当于突破外部 空间的限制

  51. 为什么C语言里卖弄没有重载?

  52. 指针与引用的不同的

  53. 多使用override,finaldelete关键字

  54. 可以在返回值处写auto关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    template<typename T1,typename T2,typename T3>
    auto add(T1 a,T2 b,T3 c){
    return a+b+c;
    }

    auto add(int a,int b){
    return a+b;
    }


    int main(){
    cout<<add(1,5.8,-8)<<endl;
    cout<<add(8,2,-9)<< endl;
    return 0;
    }

  55. 使用可变参数模板进行add操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<typename ...Args>
    auto add(Args...args){
    return (args + ...);
    }

    int main(){
    cout<<add(1,5.8,-8)<<endl;
    cout<<add(8,2,-9)<< endl;
    return 0;
    }

  56. 当对vector使用clear后,将不再有vector

  57. .o文件是已经编译完成的文件,这个阶段会发生未声明错误

    如果是未定义,则是发生在链接阶段

  58. 字符串的初始化有很多形式

    1
    2
    3
    4
    5
    6
    7
    int main(){
    string str1{"i'm august"};
    string str2{"hello,world",5};
    string str3{str2,0,5};

    return 0;
    }

c++随记
https://tsy244.github.io/2023/04/11/cpp/c++随记/
Author
August Rosenberg
Posted on
April 11, 2023
Licensed under