zoukankan      html  css  js  c++  java
  • [C++Primer] 第二章 变量和基本类型

    第二章 变量和基本类型

    引用

    1. 引用定义的时候必须初始化。

    2. 引用初始化之后无法重新绑定到其它对象上。

    3. 引用本身并不是对象,所以没有指向引用的引用(不管如何多层引用,引用的还是源对象)

    下面用一个简单的例子说明:

    int a=1;
    int& b=a;
    cout<<&a;//00D4FE0C
    cout<<&b;//00D4FE0C
    

    可以看出对源对象a进行取地址和对b进行取地址的结果是一样的(实际上,引用的本质就是一个常量指针,即 int * const ptr类型

    指针

    1. 指针本身就是个对象,允许对指针本身进行复制和拷贝操作。
    2. 指针定义时可以不赋初值,也可以指向nullptr,同时,其值也可以为未确定的值。
    3. 指针在其生命周期内可以指向不同的对象。

    下面用一个简单例子说明:

    int a=1;
    int& b=a;
    cout<<&a;//012FFD64
    cout<<&b;//012FFD58
    

    可以看出指针本身的地址和源对象的地址是不一样的,这是指针和引用的一个重要区别。

    nullptr和NULL

    nullptr是C++ 11 引入的新的关键字,而NULL是一个值为0的预处理变量,即:

    #define NULL 0
    

    在程序中最好使用nullptr关键字而非NULL,例如下面的例子:

    #include <iostream>
    
    void go(int num)
    {
        std::cout << "number" << std::endl;
    }
    
    void go(void *p)
    {
        std::cout << "ptr" << std::endl;
    }
    
    void main()
    {
        void *p = NULL;
    
        go(p);//ptr
    
        go(NULL);//number 得到的很有可能不是想要的答案
    
        go(nullptr);//ptr
    
        system("pause");
    }
    

    void*指针

    void*是一种特殊的指针类型,可以存放任意对象的地址,但是我们不了解其中存放的对象到底是什么类型的,我们可以用此指针来保存对象,而void表明我们我们用什么类型来解释这段存储空间中的对象(包括对象的长度),但我们无法对这个对象进行操作,因此在进行对象操作之前我们需要先对该指针进行类型转换。

    int a=1;
    void* b=&a;
    cout << *(int*)b << endl;// 1
    

    const限定符

    const关键字用来表示一个常量,例如:

    const int a=100;
    

    编译器会在编译过程中把所有用到这个变量的地方全部替换成常数100。

    默认情况下,const对象仅仅在当前文件内有效,如果多个文件中出现了同名的const变量,那么等于在不同文件中分别定义了独立的变量。(如果需要多个文件之间共享,那么我们需要使用extern关键字)

    • const结合指针

    通过下面的代码区分const结合指针的区别:

    int a=10;
    const int * ptr=&a;// ptr本身可以指向别的对象,但不能通过ptr修改a的值
    int const * ptr=&a;// 同上
    int * const ptr=&a;// ptr本身不能改变,但是可以通过ptr修改a的值
    

    类型别名

    • typedef

    我们可以使用typedef来定义类型别名,这样我们就可以把越写越长的变量类型用短的单词代替,例如:

    typedef int in;//in就是int的别名
    typedef in i,*ptr;//i就是int的别名,ptr是int*的别名
    
    #include <iostream>
    using namespace std;
    class A
    {
    public :
    	void test() { cout << 1; }
    };
    int main()
    {
    	auto i=new A();
    	typedef void (A::*ptr)(); //ptr为指向A成员函数的指针类型,指向的函数的参数和返回值都为空
    	ptr a= &A::test;
    	(i->*a)();//输出1
    }
    
    

    同时我们需要注意typedef与define的一个重要区别:

    typedef char* type;
    #define def char*
    type i1, i2;    // i1 和 i2 均为指向 char 的指针
    def  j1, j2;   // j1 为指向 char 的指针, 但 j2 为char 型变量
    
    • using

    C++11新标准提出了新的方法,使用using来取别名:

    using newInt= int;
    newInt a=10;
    

    auto类型说明符

    自动分析表达式类型。

    auto i=1;//int类型
    
    • 一般会忽略顶层const,保留底层const

    顶层const:指针本身是常量;

    底层const:指针指的对象是常量;

    int i=0;
    int * const p1=&i; 		//这是顶层const,不能改变p1的值
    const int ci=42;		//顶层const,不能改变ci的值
    const int *p2=&ci;		//底层const,不能改变p2的值
    const tint * const p3=p2;//左边是底层const,右边是顶层const
    const int & r=ci;		//用于声明引用的都是底层const
    

    个人理解:定义的变量本身不能改变,则为顶层const,反之则为底层const(引用除外,引用都是底层const)

    再看auto推断规则:

    int i=1;
    const int ci=i;
    const int &cr=ci;
    auto b=ci;//b是一个整数,顶层const忽略
    auto c=cr;//c是一个整数,cr是ci别名,ci是顶层const
    auto d=&i; //d是一个整型指针
    auto e=&ci; //e是一个整型常量指针,对常量对象取地址是一种底层const,也就是const int* e=&ci;
    

    再看一个例子:

    int a=1;
    const int* ptr1=&a;
    auto res1=ptr1;//底层const保留,res1类型为const int*
    
    int* const ptr2=&a;
    auto res2=ptr2;//顶层const忽略,res2类型为int*
    

    如果希望推到出的auto类型是一个顶层const,那么需要明确指出:

    const auto f=ci;//这时候才会带上const,f类型为const int
    

    decltype

    decltpye用于选择并返回操作数的数据类型,在这个过程中编译器分析表达式得到类型,但是不计算表达式实际的值。

    decltype(function()) sum=x;	//sum的类型就是function函数返回值的类型
    
    • decltype和auto的区别

    decltype返回该变量的类型,包括顶层const和引用在内。

    const int ci=0,&cj=ci;
    decltype(ci) x=0;	// x的类型是const int
    decltype(cj) y=x;	// y的类型是const int&,y绑定到变量x
    decltype(cj) z;		// 错误,z是一个引用,必须初始化
    

    需要指出,引用从来都是作为其所指对象的同义词出现,只有用在decltype处是个例外。

    此外,对于decltype所用的表达式来说,多加了一对括号和不加括号时会有区别,如果给变量加上了一层或者多层的括号,那么编译器会把它当作一个表达式,变量时一种可以作为赋值语句左值的特殊表达式,所以这样的decltype会得到引用类型。

    decltype((i)) d;	// 错误,d是int&,必须初始化
    decltype(i) e;		// 正确,e是一个int
    

    decltype((variable))的结果永远是引用,而decltype(variable)的结果只有在variable本身是一个引用时才是引用。

    预处理器

    C++程序可以使用#define指令把一个名称设定为预处理变量,用#ifdef表示在变量定义的时候为真,#ifndef为当变量未定义时为真,一旦检查结果为真,则执行后续操作到#endif为止。

    #ifndef HEAD_H
    #define HEAD_H
    
    ... your code...
    
    #endif
    

    注意在VS中也可以使用#pragma once来表示只编译一次,但是只在windows下生效,无法跨平台。

  • 相关阅读:
    【51NOD】1135 原根
    RuntimeWarning: More than 20 figures have been opened.
    获取当前文件夹下文件个数
    U盘装win10(我们无法创建新的分区,也找不到现有分区)
    我们无法创建分区也找不到现有的分区
    装系统——出现“invalid partition table”提示的原因
    python帮助文档的浏览
    opencv-python ,CV2读取中文路径和中文名称图片无结果,解决办法
    pyx文件编译
    安装polygon
  • 原文地址:https://www.cnblogs.com/lizhenghao126/p/11052117.html
Copyright © 2011-2022 走看看