zoukankan      html  css  js  c++  java
  • C++基础

    命名空间

    主要是为了解决名称冲突的问题

    引用

    变量的别名

    引用和指针的区别:

      1.指针是个变量,可以把它再赋值指向别的地址

      2.建立引用的时候必须初始化,并且绝不会再关联其他不同的变量。而指针可以一开始就赋值空,之后可以再改变指向其他地方。

    由于指针也是变量,所以,可以有指针变量的引用,比如下面的看着有点诡异的代码

    int* a = NULL;
        int*& ra = a;//表示int*的引用ra初始化为a
        int b = 9;
        ra = &b;//OK,ra是a的一个别名,是一个指针
    • void引用是不合法的

      void& a = 3;void只是在语法上相当于一个类型,本质上不是类型,没有任何一个变量或者引用的类型的是void

    • 不能建立引用的数组
    int a[10] ={0};
    int& ra[10] = a;//error
    • 没有引用的指针和引用的引用
    int a ;
    int& ra = a;
    int& *p = &ra;//error启动定义一个引用的指针
    • 有空指针,但没有空引用哇

    无符号数Unsigned

    这个操蛋的地方在于不能出现一个负值,如果一个int 和一个 unsigned出现在一个表达式里面的话会出现意想不到的效果,比如这个int是一个负值的时候,就会自动转换为unsigned,也就是通常会变成一个很大的整数;在比如一个负的unsigned和一个正的int进行比较的话,unsigned也会自动转换成一个合法的unsigned。

    #include <iostream>
    using namespace std;
    
    int main(){
        int i = 2;
        unsigned j = -1;
        if (i > j)
          cout << "is true" << endl;
        else
          cout << "is false" << endl;
        cout << "j = " << j << endl;
        return 0;
    }

    is false
    j = 4294967295

    所以一定切记,不要让unsigned成为一个负数

    引用的参数传递

    • 传递引用给函数与传递指针的效果是一样的。都能改变变量的值
    • 用引用作为参数比使用指针有更清晰的语法
    • 使用引用作为参数返回值,给函数带来的意义

        1.函数只能返回一个值,如果要返回两个值怎么办?可以用引用给函数传递两个参数,然后由函数往目标中填入正确的值

        2.函数返回值时要返回一个值的副本,而用引用返回时不需要生成副本,所以提高了效率

        注意:如果返回不在作用域范围内的变量或者引用那就有问题了。这与返回一个局部作用域指针的性质一样严重,比如

    指针

    关于常量指针

    int a = 1 , b = 2;

    const int *p = &a;  //p是表示指向一个const int数,不过指向一个非const的int也是可以的

    p = &b; //是可以指向别的对象的,这里的const是底层const

    *p = 5;// error !!

    其实可以这样理解,const int *p 就表示它要指向一个const int 而这个数是不能被改变的,所以理所应当,*p是不能变的,它不需要去关心那个数到底是不是const,虽然前面也说,p是可以指向非const的

    而如果换成

    int *const p = &a; //这里的p就是代表一个指向int的常量指针,这里的const称作顶层const,修饰的是p

    p = &b; // error , p是const不能改变,所以p不能再指向其他地方了

    *p = 434; // 可以,int是可以改变的

    const int *const p = &a ; //当然这样就 *p 和p都不能改变了

    constexpr

    常量表达式。如果修饰的是指针的话,那么只跟指针有关,跟指针所指的对象无关,比如

    int i = 3 , j = 22;

    constexpr int *p = &i; //这里可以指向const 也可以指向非const

    p = &j; // error

    *p = 4342; //可以

    auto

    可以让编译器替我们分析表达式所属的类型。

    比如:

    auto a = 4 + 2;
    auto da = 4.3 + 3.3;
    cout << "a = " << a << endl; //6
    cout << "da = " << da << endl;//7.6

    这个东西注意一个地方,auto能在一条语句中声明多个变量,但是这一条语句中的所有变量都必须同一个类型。

    你不能这样搞:auto s = 0 , f = 3.3; // ERROR

    string

    1.string的size函数返回的不是一个int!!!!返回的是一个string::size_type类型的值。尽管不太清楚这个类型的细节,但是可以肯定:它是一个unsigned类型的值。所以通常用auto或者decltype来推断。比如统计一个string里面的标点符号

    #include <iostream>
    using namespace std;
    int main(){
        string str = "Hello World!!!!";
        decltype(str.size()) punct_cnt = 0;
        for (auto c : str)
          if (ispunct(c))
            punct_cnt++;
        cout << punct_cnt << " punct in str" << endl;
        return 0;
    }

    4 punct in str

    一个问题

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main(){
        unsigned scores[11];
        unsigned grade;
        while (cin >> grade)
          if (grade <= 100)
            ++scores[grade/10];
        for (auto i : scores)
          cout << i << endl;
        return 0;
    }

    为什么会有问题呢??? 为什么scores一定要初始化呢?scroes[11] = {};

    强制转换

    形式如下

    cast-name<type>(expression); type是要转换的目标类型,expression是待转换的值。cast-name是static_cast、dynamic_cast、const_cast、reinterpret_cast中一中

    const_cast

    改变运算对象的底层const,将常量对象转换成非常量对象的行为。举个例子

    #include <iostream>
    using namespace std;
    
    int main(){
        int i = 3;
        const int *ip = &i; 
    
        cout << *ip << endl;
        //*ip = 423;
        //cout << *ip << endl; //错误 *ip不能变
        int *p = const_cast<int*>(ip);
        *p = 23; 
        cout << *p << endl;   //23
        cout << "i = " << i << endl; // i = 23
        return 0;
    }

    上面本来是不能通过*p来改变对象的值的,但是const_cast等于是将const去掉了获取了写权限

    要注意的是  i 本来就是可以改变的 ,如果把 i 改成const ,如:const int i = 3; 其他都不变,那么程序编译运行是没有问题的, *p也还是23 ,但是 i 不会变,还是3。

    分离式编译

    即允许我们把程序分割到几个文件中去,每个文件单独编译。程序复杂的时候,会希望把程序各个部分分别存储到不同的文件中。比如:

    在同一个目录下,放了自己写的头文件 test.h ,还有 test.h 中声明的函数定义文件 fun.cpp , 以及放了main函数的 t.cpp

    #include <iostream>
    #include "test.h"
    
    using namespace std;
    int main(){
        cout << fun(4) << endl;
        return 0;
    }
    #include "test.h"
    
    int fun(int i){ 
        return 2*i;
    }
    int fun(int i);

    分离式编译的步骤如下:

    g++ -c t.cpp fun.cpp

    这里的-c参数是 Compile and assemble, but do not link(编译并汇编,但不链接),编译成功后会输出2个.o的文件,一个是t.o,一个是fun.o

    然后再链接成一个可执行文件

    g++ t.o fun.o -o t

    后面这个 t 是代表要生成的可执行文件的名字,这个参数是必须的,不能省,完成后会生成一个名为t的可执行文件

  • 相关阅读:
    40_接口类型的使用
    39_方法值和方法表达式
    38_方法的重写
    37_匿名字段方法的继承
    36_方法集的使用
    文件方式实现完整的英文词频统计实例
    组合数据类型练习,英文词频统计实例上
    英文词频统计预备,组合数据类型练习
    凯撒密码、GDP格式化输出、99乘法表
    字符串基本操作‘’
  • 原文地址:https://www.cnblogs.com/i-love-kobe/p/6057552.html
Copyright © 2011-2022 走看看