• day2学习笔记


    一 布尔类型
    1 bool类型是C++中的基本数据类型,专门表示逻辑值,逻辑真用true表示,逻辑假false表示
    2 bool类型在内存占一个字节:1表示true,0表示false
    3 bool类型变量可以接收任意类型表达式结果,其值非0则为true,为0则为假

    #include   
    using namespace std;  
    int main(void){  
        bool b = false;  
        cout << "b=" << b << endl;//0  
        cout << "size=" << sizeof(b) << endl;//1  
      
        b = 3 + 5;  
        cout << "b=" << b << endl;//1  
        b = 1.2 * 3.4;  
        cout << "b=" << b << endl;//1  
        int* p = NULL;//NULL->(void*)0  
        b = p;  
        cout << "b=" << b << endl;//0  
       return 0;  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    八 C++的函数
    1 函数重载(overload)
    1)定义
    在相同作用域,可以定义同名的函数,但是参数必须有所区分,这样函数构成重载关系.
    注:函数重载和返回类型无关。

    eg:实现图形库中一些绘图函数
    //C语言

    void drawRect(int x,int y,int w,int h){}
    void drawCircle(int x,int y,int r){}
    
    //C++语言
    void draw(int x,int y,int w,int h){}
    void draw(int x,int y,int r){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    #include   
    using namespace std;  
    int func(int i){  
        cout << "func(int)" << endl;  
    }  
    void func(int a,int b){  
        cout << "func(int,int)" << endl;  
    }  
    void func(int i,float f){  
        cout << "func(int,float)" << endl;  
    }  
    int main(void){  
        func(10);  
        func(10,20);  
       //func(10,3.14);//歧义错误,3.14默认当做double  
        func(10,3.14f);//func(int,float)  
       //由函数指针类型决定匹配的重载版本  
        void (*pfunc)(int,float) = func;  
        pfunc(10,20);   
        return 0;  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2)函数重载匹配
    调用重载关系的函数时,编译器将根据实参和形参的匹配程度,自动选择最优的重载版本,当前g++编译器匹配一般规则:
    完全匹配>=常量转换>升级转换>降级转换>省略号

    #include   
    using namespace std;  
    //char->int:升级转换  
    void bar(int i){  
        cout << "bar(1)" << endl;  
    }  
    //char->const char:常量转换  
    void bar(const char c){  
        cout << "bar(2)" << endl;  
    }  
    //short->char:降级转换  
    void hum(char c){  
        cout << "hum(1)" << endl;  
    }  
    //short->int:升级转换  
    void hum(int i){  
       cout << "hum(2)" << endl;  
    }  
    //省略号匹配  
    void fun(int i,...){  
       cout << "fun(1)" << endl;  
    }  
    //double->int:降级转换  
    void fun(int i,int j){  
        cout << "fun(2)" << endl;  
    }  
    int main(void){  
        char c = 'a';  
        bar(c);  
        short s = 100;  
        hum(s);  
        fun(100,3.14);   
        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
    • 31
    • 32
    • 33
    • 34

    3)函数重载原理
    C++的编译器在编译函数时,会进行换名,将参数表的类型信息整合到新的函数名中,因为重载关系的函数参数表有所区分,换出的新的函数名也一定有所区分,解决了函数重载和名字冲突的矛盾。

    笔试题:C++中extern "C"作用?
    在C++函数声明时加extern "C",要求C++编译器不对该函数进行换名,便于C程序直接调用该函数.
    
    注:extern "C"的函数无法重载。
    
    • 1
    • 2
    • 3
    • 4

    2 函数的缺省参数(默认实参)
    1)可以为函数参数指定缺省值,调用该函数时,如果不给实参,就取缺省值作为默认实参。
    void func(int i,int j=0/缺省参数/){}
    2)靠右原则:如果函数的某个参数带有缺省值,那么该参数右侧的所有参数都必须带有缺省值。
    3)如果函数的声明和定义分开写,缺省参数应该写在函数的声明部分,而定义部分不写

    #include   
    using namespace std;  
    //函数声明  
    void func(int a,int b = 20,int c = 30);  
    //void func(int i){}//注意歧义错误  
    int main(void){  
       func(11,22,33);  
       func(11,22);//11 22 30  
       func(11);//11 20 30  
       return 0;  
    }  
    //函数定义  
    void func(int a,int b/*=20*/,int c/*=30*/){  
       cout << "a=" << a << ",b=" << b << ",c="  
               << c << endl;  
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3 函数的哑元参数
    1)定义函数时,只有类型而没有变量名的形参被称为哑元
    void func(int){…}
    2)需要使用哑元场景
    –》在操作符重载函数中,区分前后++、-- //后面讲
    –》兼容旧的代码

    算法库:void math_func(int a,int b){...}
    使用者:
    	int main(void){
    		...
    		math_func(10,20);
    		...
    		math_func(10,20);
    		...
    	}
    -----------------------------------------
    升级算法库:void math_func(int a,int/*哑元*/){...}
    使用者:
    	int main(void){
    		...
    		math_func(10,20);
    		...
    		math_func(10,20);
    		...
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4 内联函数(inline)
    1)使用inilne关键字修饰的函数,即为内联函数,编译器将会尝试进行内联优化,可以避免函数调用开销,提高代码执行效率.
    inline void func(void){…}
    2)使用说明
    –》多次调用小而简单的函数适合内联优化
    –》调用次数极少或大而复杂的函数不适合内联
    –》递归函数不能内联优化
    –》虚函数不能内联优化//后面讲

    注:内联只是一种建议而不是强制的语法要求,一个函数能否内联优化主要取决于编译器,有些函数不加inline修饰也会默认处理为内联优化,有些函数即便加了inline修饰也会被编译器忽略。

    九 C++动态内存管理
    1 回顾C语言动态内存管理
    1)分配:malloc()
    2)释放:free()

    2 C++动态内存管理
    1)分配:new/new[]
    2)释放:delete/delete[]

    #include   
    using namespace std;  
    int main(void){  
        //动态分配内存保存1个int数据  
       //int* pi = (int*)malloc(4);//C  
        int* pi = new int;//C++  
        *pi = 123;  
        cout << *pi << endl;  
        //free(pi);  
        delete pi;//防止内存泄露   
        pi = NULL;//避免野指针  
        //动态分配内存同时初始化  
        int* pi2 = new int(200);  
       cout << *pi2 << endl;//200  
        (*pi2)++;  
        cout << *pi2 << endl;//201  
        delete pi2;  
        pi2 = NULL;  
      
       //动态分配内存保存10个int  
        //int* parr = new int[10];    
        //new数组同时初始化,需要C++11支持  
        int* parr =   
            new int[10]{1,2,3,4,5,6,7,8,9,10};  
        for(int i=0;i<10;i++){  
            //*(parr+i) = i+1  
           //parr[i] = i+1;  
            cout << parr[i] << ' ';  
        }  
        cout << endl;  
        delete[] parr;  
       parr = NULL;    
       return 0;  
    }  
    /
    #include   
    using namespace std;  
      
    int main(void){  
        int* p1;  
        //delete p1;//delete野指针,危险!    
        int* p2 = NULL;  
        delete p2;//delete空指针,安全,但是无意义  
      
        int* p3 = new int;  
        delete p3;  
        delete p3;//不能多次delete同一个地址  
        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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    十 C++引用(Reference)
    1 定义
    1)引用即别名,引用就是某个变量别名,对引用操作和对变量本身完全相同.
    2)语法
    类型 & 引用名 = 变量名;
    注:引用必须在定义同时初始化,而且在初始化以后所绑定的目标变量不能再做修改.
    注:引用类型和绑定目标变量类型要一致。
    eg:
    int a = 10;
    int & b = a;//b就是a的别名
    b++;
    cout << a << endl;//11
    a++;
    cout << b << endl;//12

    int c = 123;
    b = c;//仅是赋值,只是改变了b的值而已,并没有改变绑定目标,&b=c这样才是改变绑定目标
    cout << a << endl;//a,b的值都是123
    
    • 1
    • 2
    • 3
    #include   
    using namespace std;  
    int main(void){  
       int a = 10;  
       int& b = a;//b引用a,b就是a的别名  
       cout << "a=" << a << ",b=" << b << endl;  
       cout << "&a=" << &a << ",&b=" << &b<<endl;//证明其实 两个地址 就是一个地址  
        b++;  
        cout << "a=" << a << ",b=" << b << endl;  
          
        //int& r;//error,引用定义时必须初始化  
       int c = 20;  
        b = c;//ok,但不是修改引用目标,仅是赋值  
      
        cout << "a=" << a << ",b=" << b << endl;  
       cout << "&a=" << &a << ",&b=" << &b<<endl;  
     
        //char& rc = c;//error,引用类型和目标要一致  
       return 0;  
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2 常引用
    1)定义引用时可以加const修饰,即为常引用,不能通过常引用修改目标变量.
    const 类型 & 引用名 = 变量名;
    类型 const & 引用名 = 变量名;//和上面等价

    int a = 10;
    const int& b = a;//b就是a常引用
    cout << b << endl;//10
    b++;//error
    
    • 1
    • 2
    • 3
    • 4
    #include   
    using namespace std;  
    int main(void){  
        //int& r1 = 100;//error  
        const int& r1 = 100;//ok  
        cout << r1 << endl;//100  
      
        int a=10,b=20;  
        //int& r2 = a+b;//error  
       //r2引用的是a+b表达式结果的临时变量(右值)  
        const int& r2 = a+b;  
        cout << r2 << endl;//30    
        return 0;  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2)普通引用也可以称为左值引用,只能引用左值;而常引用也可以称为万能引用,既可以引用左值也可以引用右值。

    3)关于左值和右值
    左值(lvalue):可以放在赋值表达式左侧,可以被修改
    右值(rvalue):只能放在赋值表达式右侧,不能被修改

    #include   
    using namespace std;  
    int func(void){  
        int num = 123;  
        cout << "&num:" << &num << endl;  
        return num;//临时变量=num  
    }  
    int main(void){  
       int c = 100;  
        //1)将c转换为char,转换结果保存到临时变量  
        //2)rc实际要引用不是c而是临时变量  
       //char& rc = c;//error  
       const char& rc = c;//ok  
        cout << "&c:" << &c << endl;  
        cout << "&rc:" << (void*)&rc << endl;  
      
        //rf = 临时变量  
        //int& rf = func();//error  
        const int& rf = func();  
        cout << "&rf:" << &rf << endl;  
        cout << rf << endl;//123   
        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

    3 引用型函数参数
    1)可以将引用用于函数的参数,这时形参就是实参别名,可以通过形参直接修改实参的值;同时还能避免函数调用时传参的开销,提高代码执行效率。
    2)引用型参数有可能意外修改实参的值,如果不希望修改实参,可以将形参声明为常引用,提高效率的同时还可以接收常量型的实参

    #include   
    using namespace std;  
    struct Teacher{  
        char name[100];  
       int age;  
        double salary;  
    };  
    //常用就是const修饰,避免被修改
    void printInfo(const Teacher& t){  
        cout << t.name << "," << t.age/*++*/<< ","  
            << t.salary << endl;  
    }  
    int main(void){  
        const Teacher minwei={"???",45,80000.5};  
        printInfo(minwei);  
        printInfo(minwei);  
        return 0;  
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4 引用型函数返回值
    1)可以将函数的返回类型声明为引用,这时函数的返回结果就是return后面数据的别名,可以避免返回值带来的开销,提高代码执行效率.
    2)如果函数返回类型是左值引用,那么函数调用表达式结果就也将是一个左值。
    注:不要从函数中返回局部变量的引用,因为所引用的内存会在函数返回以后被释放,使用非常危险!可以在函数中返回成员变量、静态变量、全局变量或者动态内存分配的引用。

    int& func(void){
    	...
    	return num;
    }
    func() = 100;//ok
    
    • 1
    • 2
    • 3
    • 4
    • 5
    #include   
    using namespace std;  
    struct A{  
        int data;  
        int& func(void){  
            return data;  
        }  
        int& func2(void){  
            int num = 100;  
            return num;//危险!!  
        }  
    };  
    int main(void){  
        A a = {100};  
        cout << a.data << endl;//100  
        //a.data = 200  
        a.func() = 200;//ok   
        cout << a.data << endl;//200  
        return 0;  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    5 引用和指针
    1)如果从C语言角度看待引用的本质,可以认为引用就是通过指针实现的,但是在C++开发中,推荐使用引用,而不推荐使用指针.
    int i = 100;
    int* const pi = &i;
    int& ri = i;
    pi <=等价=> ri
    2)指针可以不做初始化,其目标可以在初始化以后随意改变(指针常量除外),而引用必须做初始化,而且一旦初始化所引用的目标不能再改变.
    int a=10,b=20;
    int
    p;//ok
    p = &a;
    p = &b;
    --------------------
    int& r;//error
    int& r = a;
    r = b;//ok,但不是修改引用目标,仅是赋值运算

    //下面内容了解
    3)可以定义指针的指针(二级指针),但是不能定义引用的指针.
    int a = 10;
    int* p = &a;
    int** pp = &p;//二级指针
    ------------------------
    int& r = a;
    int&* pr = &r;//error,引用的指针
    int* pr = &r;//ok,仅是普通指针

    4)可以指针的引用(指针变量别名),但是不能定义引用的引用。
    int a = 100;
    int* p = &a;
    int* & rp = p;//ok,指针的引用
    -----------------------------
    int& r = a;
    int& & rr = r;//error,引用用的引用
    int& rr = r;//ok,但是仅是一个普通引用

    5)可以指针数组,但是不能定义引用数组
    int i=10,j=20,k=30;
    int* parr[3] = {&i,&j,&k};//ok,指针数组
    int& rarr[3] = {i,j,k};//error

    6)可以定义数组引用(数组别名)
    int i=10,j=20,k=30;
    int arr[3] = {i,j,k};
    int (&rarr)[3] = arr;//ok, 数组引用

    7)和函数指针类似,也可以定义函数引用(函数别名)
    void func(int i){}
    int main(void){
    void (*pf)(int) = func;//函数指针
    void (&rf)(int) = func;//函数引用
    pf(100);
    rf(100);
    }

    1.#include <iostream>  
    2.using namespace std;  
    3.  
    4.int main(void){  
    5.    int* pi = NULL;  
    6.    //char c = (long)pi;//C风格强转  
    7.    char c = long(pi);//C++风格强转  
    8.  
    9.    //静态类型转换  
    10.    //char c2 = static_cast(pi);//不合理  
    11.    void* pv = pi;  
    12.    pi = static_cast<int*>(pv);//合理  
    13.    return 0;  
    14.}  
    
    1.#include <iostream>  
    2.using namespace std;  
    3.int main(void){  
    4.    //volatile是标准C语言的关键字  
    5.    //被volatile修饰的变量表示易变的,告诉编译  
    6.    //器每次使用该变量时,都要小心从内存中读取,  
    7.    //而不是取寄存器的副本,防止编译器优化引发  
    8.    //的错误结果.  
    9.    volatile const int i = 100;  
    10.    int* pi = const_cast<int*>(&i);  
    11.    *pi = 200;  
    12.    cout << "i=" << i << ",*pi=" << *pi  
    13.        << endl;//200,200  
    14.    cout << "&i=" << (void*)&i << ",pi=" <<   
    15.         pi << endl;  
    16.  
    17.    return 0;  
    18.}  
    
    1.#include <iostream>  
    2.using namespace std;  
    3.int main(void){  
    4.    //"\000"-->'\0'  
    5.    char buf[] = "0001\00012345678\000123456";  
    6.    struct HTTP{  
    7.        char type[5];  
    8.        char id[9];  
    9.        char passwd[7];  
    10.    };  
    11.    HTTP* pt = reinterpret_cast<HTTP*>(buf);  
    12.    cout << pt->type << endl;//0001  
    13.    cout << pt->id << endl;//12345678  
    14.    cout << pt->passwd << endl;//123456  
    15.  
    16.    return 0;  
    17.}  
    
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 相关阅读:
    14:00面试,14:06就出来了,问的问题过于变态了。。。
    速锐得解码新款坦克300网关(Gateway)采集CAN总线数据实操过程
    最优化基础知识总结(1)
    使用JDBC访问微软Access实例
    shell脚本命令
    PE文件硬编码代码注入
    strimzi实战之一:简介和准备
    [洛谷] P1141 01迷宫
    高级架构师_Redis_第2章_数据类型与底层数据结构
    谁不想要一个自己的博客网站呢 - 搭建博客网站wordpress
  • 原文地址:https://blog.csdn.net/qq_27182175/article/details/126018423