C++知识点总结

来源:互联网 发布:linux安装vftp 编辑:程序博客网 时间:2024/06/06 09:58

C++基础

  1. C++注重类型,进行严格的类型检查,在C++中,不同类型的指针不能直接赋值,必须强制转换;
  2. C语言的全局变量有声明和定义的差别,声明可以有多个,定义只能由一个,C++全局变量和静态全局变量没有声明和定义的差别;
  3. typeid(num).name();可以打印出num的数据类型;
    decltype(num) numA(10);decltype可以将num的数据类型作为numA的类型;
  4. 结构体和共用体
    1. 结构体内部成员变量可以有默认参数值,匿名结构体不允许初始化,结构体可以实现封装,继承,多态;
    2. union
      1. 本质是一个类,其内部可以有函数,内部数据是共享内存的,但是不能继承;
      2. union 具备结构体的所有功能;
  5. 内联函数
    1. 内联函数不能作为函数调用,而是直接把内联函数的代码嵌入到调用的语句中;
    2. 内联函数适合函数代码很少,并且频繁的大量调用;
    3. 内联函数只是对编译器的建议,函数声明为内联并不一定称为内联;
    4. 内联取代宏
      1. 内联函数在运行时可调试,而宏定义不可以;
      2. 编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义不会;
      3. 内联函数可以访问类的成员变量,而宏定义不能;
      4. 在类中声明同时定义的成员函数,自动转化为内联函数;
    5. 一般情况下,对内联函数做如下限制:
      1. 不能有递归,不能包含静态变量,不能包含循环;
      2. 不能包含switch和goto语句,不能包含数组;
  6. 引用

    1. 引用就是一个变量的别名,而不是地址;
    2. 引用作为函数的参数,没有出栈,入栈操作,所以效率更高;
    3. 左值和右值
      1. 左值是可以放在赋值号左边被赋值的值,必须在内存有实体,左值引用使用指针实现;
    4. 右值引用,可以节约内存拷贝,内存优化所必须,主要用在函数中较大的对象作为形参,形式: 类型 && 变量;
    5. 引用实例

      1. int (&ra)[10] (a) 引用一维数组
      2. int (&ra)[2][5] (a) 引用二维数组
      3. 通过函数改变函数指针,引用一个函数指针

        void change(int (*&rp)(int a,int b)){    rp = jian;    cout << rp(1, 2) << endl;}
      4. 返回一个函数指针的引用

        int(**& changep(int(*&rp)(int, int)))(int, int) {    rp = jian;    return rp;}
    6. 引用的本质是指针,直接sizeof引用,就是求引用的数据的大小,代码区的函数不计入结构体的sizeof;
  7. const变量和函数
    1. const限定变量类型
      1. int const *p1,const int *p1;
        p1指向常量的指针,指向的数据不可以修改,可以改变其指向的地址—>可读不可写权限;
      2. int *const p1;
        p1指向指针常量的指针,指针不可以修改,但是指针指向的变量的值可以修改—>可读可写权限;
      3. const int * const p1;
        p1指向的指针和指针指向的值都是常量,不可以修改;
    2. 函数的形参可以是const T& val,或者返回指向常量类型的指针,保证其使用或返回之后不会被修改;
    3. 对于const int a(10);这个变量是直接从常量表读取的,没有直接从内存读取,如果使用const_cast对其进行修改,则真实的内存已经修改,但是编译器会优化,不会从内存读取;
    4. const 动态监测类型,实现赋值,赋值会自动进行类型转换,避免类型不一致出错,const在内存有实体,有的编译器会直接获取常量的值进行替换
    5. gcc 和 VC最新版本都是从代码区存储常量表,常量在寄存器产生,不会从内存读取,属于编译器的优化;
  8. new 和 delete
    1. 基本概念
      1. new 和 delete是C++内建的操作符,不需要任何头文件,用new分配的数组必须用delete释放;
      2. 空类占一个字节,表示自己存在
      3. 没有分配内存,构造和析构无意义;
      4. 全局的new和delete监视所有的释放和分配,局部的new 和 delete监视某个类的所有分配和释放;
      5. 局部的new 会调用全局的new,全局的new会调用malloc分配内存内存,之后会调用构造函数;delete时调用析构函数会先调用局部的delete,然后调用全局的delete,最后全局的delete调用free函数;
  9. 函数重载和默认参数
    1. 函数的参数个数,参数的类型不同,参数的顺序不同,可以实现重载,重载与返回值无关;
    2. 函数指针没有默认参数,必须全部输入数据;
    3. 遇到具有相同非默认参数的函数无法调用时,可以通过定义函数指针指向不同的函数的形式进行调用;
    4. 函数的名称是一样的,但参数列表不同,可以实现重载;函数参数列表形同,但返回值不同,不可以实现重载;
    5. 函数重载与返回值类型无关
  10. 函数模板与自动数据类型

    1. 带有多个参数的函数模板形式如下:

      template<typename T>T sum(int count,T data1 ...){    va_list arg_ptr; //参数列表的指针    va_start(arg_ptr, count);//限定从count开始,限定多少个参数    T sumres(0);    for (int i = 0; i < count; i++){        sumres += va_arg(arg_ptr, T);    }    va_end(arg_ptr);//结束    return sumres;}
    2. auto与函数模板

      //如果要使用函数模板,需要实例化即:函数名<实例化类型>(参数...);template<class T1, class T2>//根据类型获取类型auto get(T1 data, T2 bigdata)->decltype(data * bigdata){    return data * bigdata;}//decltype可以根据括号内的数据类型导出返回的数据类型,函数的参数不允许使用自动变量;
    3. 通用可变参数的函数模板

      void showall(){}//空函数,接口,不能去掉,否则不能编译,最后结束递归template<typename T, typename...Args>void showall(const T &value, const Args &...args){    //Args通用的数据类型,加上const使数据不能修改,也可以加上引用    cout << value << endl;    showall(args...);//继续传递,需要一个同名空函数结束递归} //调用方式如下:int num1 = 10, num2 = 9, num3 = 11;double db1 = 10.3, db2 = 20.3;char str[20] = "gsw";char ch = 'S';showall(num1,num2,num3);showall(db1, db2, num1, ch, str);
    4. 函数模板的重载

      template<typename T>void showarray(array<T,10> myarray,int n){    cout << "TTTTT" << endl;    for (int i = 0; i < n; i++){        cout << myarray[i] << '\t';    }    cout << endl;}template<typename T>void showarray(array<T*, 10> myarray, int n){    cout << "T*T*T*T*T*" << endl;    for (int i = 0; i < n; i++){        cout << *myarray[i] << '\t';    }    cout << endl;}array<int, 10>intarray = { 1, 2, 3, 4, 5,6,7,8,9,10 };array<int *, 10>pintarray ;array<int **, 10>ppintarray;for (int i = 0; i < 10; i++){    pintarray[i] = &intarray[i];}for (int i = 0; i < 10; i++){    ppintarray[i] = &pintarray[i];}showarray(intarray, 5);showarray(pintarray, 5);showarray(ppintarray, 5);
  11. 类型转换

    1. static_cast
      static_cast<需要转换的数据类型>(要转换的数据) (80%情况都是它),进行一般的数据类型转换;
    2. const_cast
      const int num(10); num可以修改,无法生效,编译时候无法从内存读取;
      const int *p = num; 限定权限,只读不可写
      const_cast用于去掉常量指针或引用的const属性 (5%)
    3. reinterpret_cast
      指针转换,强类型,类型决定了数据的解析方式
    4. dynamic_cast
      用于指针之间的转换
  12. 新类型数组array
    array数据类型,array<类型,数组大小>,初始化之后数组的大小不可以改变
    array<double, 3> dbnew={ 1.1, 2.2, 33.3 };
    array<double, 3> dbnew1 = dbnew;//**可以实现数组之间的整体操作**
    array<array<int, 5>, 3> myint4 = {myint1,myint2,myint3};//3*5 二维数组的声明方法

  13. 函数包装器

    • 设计通用的执行接口,接口可以设计关卡,计数
    • 函数包装器依赖于函数模板,实现通用泛型
    • 函数代码可以内嵌在另一个函数,实现函数代码的内嵌
    //函数包装器,T是数据类型,F是函数;template<typename T, typename F>T run(T v, F f){//F是函数指针类型    static int count = 0;    count++;//计数器    cout << "执行一个参数的函数包装器" << count << "次" << endl;    if (count > 1){        T vx(0);        return vx;//可以限定函数的执行次数    }    return f(v);//函数传入参数}template<typename T, typename F>T run(T v1,T v2, F f){    return f(v1,v2);//函数传入参数}int cheng(int a, int b){    return a*b;}using std::function;//专门function<int(int, int)> fun4 = cheng;function<double(double)>fun1 = [](double u){return u * 2; };function<int(int, int)> fun3 = [](int u1, int u2){        return u1 + u2;};cout << run(num1, num2, cheng) << endl;cout << run(num1, num2, fun3) << endl; 
  14. 仿函数
    仿函数是早期的明明,C++标准所采用的新名称是函数对象。
    仿函数其实就是一个“行为类似函数”的对象,其类别定义中必须自定义(或说改写,重载)function call 运算符(operator()),拥有这样的运算符之后,我们就可以在仿函数的对象后面加上一对小括号,调用仿函数所定义的operator();

    using namespace std::placeholders;//仿函数,创建一个函数指针,引用一个结构体内部或者一个类内部的公有函数struct mystruct{    void add(int a){        cout << a << endl;    }    void add2(int a,int b){        cout << a+b << endl;    }    void add3(int a, int b,int c){        cout << a + b+c << endl;    }};//auto自动变量,地址,函数指针//第一个参数引用内部函数,第二个参数绑定一个实体对象,其他参数代表有多少个参数auto func = bind(&mystruct::add, &struct1, _1);auto func1 = bind(&mystruct::add2, &struct1,_1, _2);auto func2 = bind(&mystruct::add3, &struct1, _1, _2,_3);另一种方法mystruct struct1;//绑定机制,创建函数指针,数据私有,代码共享//函数通过调用,调用需要传递对象名,函数需要说明哪个对象才能调用void(mystruct::*p)(int a) = &mystruct::add;
  15. using 别名
    简写数据类型的时候尽量使用using,不要使用typedef;

    int add(int a, int b){    return a + b;}typedef int(*ADD)(int a, int b);using FUNC = int(*)(int a, int b);//别名机制namespace space{//隔离模板,避免冲突    template<class T> using ptr = T*;//模板的简写}using co = std::ios_base::fmtflags;//using 只可以简写数据类型//ADD p=add;//FUNC pa = add;space::ptr<int> pint(new int(3));cout << *pint << "  "<<pint<<endl;
  16. 模板元编程

    //斐波拉契数列 1 1 2 3 5 int getdata(int n){    if (n == 1 || n == 2)        return 1;    else        return getdata(n - 1) + getdata(n - 2);}//模板元把运行时消耗的时间在编译期间优化template<int N>struct data{    enum a{ res = data<N - 1>::a::res + data<N - 2>::a::res };};template<>struct data<1>{    enum a{ res = 1 };};template<>struct data<2>{    enum a{ res = 1 };};int main(){    const int myint = 40;    int num = data<myint>::res;//<>内部不可以有变量    std::cout << num << std::endl;    std::cout << getdata(40) << std::endl;    std::cin.get();    system("pause");    return 0;}
    1. 主要思想:
      利用模板特化机制实现编译期条件选择结构,利用递归模板实现编译期循环结构,模板元程序则由编译器在编译期解释执行;
    2. 优劣及适用情况
      通过将计算从运行期移至编译期,在程序启动之前做尽可能多的工作,最终获得速度更快的程序。
      模板元编程的优势在于:

      1. 以编译耗时为代价换来卓越的运行期性能(一般用于为性能要求严格的数值计算换取更高的性能)。通常来说,一个有意义的程序的运行次数(或服役时间)总是远远超过编译次数(或编译时间)。
      2. 提供编译期类型计算,通常这才是模板元编程大放异彩的地方。

      缺点:

      1. 代码可读性差,以类模板的方式描述算法也许有点抽象。
      2. 调试困难,元程序执行于编译期,没有用于单步跟踪元程序执行的调试器(用于设置断点、察看数据等)。程序员可做的只能是等待编译过程失败,然后人工破译编译器倾泻到屏幕上的错误信息。
      3. 编译时间长,通常带有模板元程序的程序生成的代码尺寸要比普通程序的大,
      4. 可移植性较差,对于模板元编程使用的高级模板特性,不同的编译器的支持度不同。
  17. 静态断言

    #define Mvoid main01()int num(10);//字节>4#ifdef Mstatic_assert(sizeof(num) >= 4, "fault ");#endif//调试代码,迅速知道代码错误在哪一行 cout << __FILE__ << endl;//指出所在文件cout << __LINE__ << endl;//提示所在行号cout << __DATE__ << endl;//源代码编译的时间cout << __TIME__ << endl;//当前的时间cout << __FUNCTION__ << endl;//显示函数名

类和面向对象

1. 面向对象

1. 类的继承实现代码重用;2. 类的封装:    1. 类的代码和数据一体化;    2. 代码的封装,限定谁可以执行,谁不可以执行;    3. 数据的封装,防止数据被意外修改;3. 类的多态,一个借口根据实际需求完成很多不同功能;

2. 友元

C++控制类对象私有部分的访问,但有时候需要在类外部访问类的私有成员,这种情况下C++提供了友元机制;1. 创建友元的步骤:    1. 将函数、类声明放在类的声明中,并在原型前加上关键字friend;        friend 返回值 函数名称(参数列表);        friend class classname;    2. 编写友元函数的定义,不需要在定义中使用关键字friend;        friend 返回值 func_name(参数列表);2. 友元的性质    1. 友元函数不属于类;    2. 友元是单向的,没有传递性;    3. 友元函数可以访问类的私有变量,还可以访问私有函数;    4. 友元函数声明有friend,定义就不需要了,或者可以定义在类的内部;

3. 构造和析构函数