• 引用和const的一些


    一,引用:某个变量的引用等价于这个变量,是这个变量的一个别名。

    #include<iostream>
    
    int main()
    {
        int a=2,b=1;
        int &c=a;//(1)定义引用时一定要初始化 
        c=3;
        std::cout<<a<<std::endl;
        c=b;  //此时并不是c引用了b而是c(实际上是a变量的值)的值变为了b变量的值,并不能改变c的引用
             //(2)引用一经初始化就不会再引用其他的变量了。 
        std::cout<<a<<std::endl;
        b=2; 
        std::cout<<a<<std::endl;
        //int &i=2;  // 错误
        //int& j=a*4; 
        /*
         *invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
         *(3)引用只能引用变量,不能引用字面常量和表达式 
         */
        return 0;
    }

    引用的实例:

    #include<iostream>
    /*
     *传值其实传的是一个实参的副本,所以实参并没有改变,而改变的是实参的副本 
     */
    void swap1(int a,int b)
    {
        int temp=a;
        a=b;
        b=temp;
    }
    /*
     *通过指针的间接引用可以改变实参的值(ps:指针形参其实也是传值的,也有一个指针副本指向实参,只不过通过这个指针也可以改变实参的值) 
     */
     
     void swap2(int* a,int* b)
    {
        int temp=*a;
        *a=*b;
        *b=temp;
    }
    /*
     *通过引用类型我们可以实际操作实参的值,因为引用就是变量的一个别名 
     */
      void swap3(int& a,int& b)
    {
        int temp=a;
        a=b;
        b=temp;
    }
    
    
    int main()
    {
        int a=2,b=1;
        swap1(a,b);
        std::cout<<"a:"<<a<<"    b:"<<b<<std::endl;
        swap2(&a,&b);
        std::cout<<"a:"<<a<<"    b:"<<b<<std::endl;
        swap3(a,b);    //调用时不用加引用 
        std::cout<<"a:"<<a<<"    b:"<<b<<std::endl;
        return 0;
    }

    函数返回引用类型

    #include<iostream>
    int n=3;
     
    int& reValue()
    {
        return n;
    }
    
    int main()
    {
        reValue()=40;
        std::cout<<n<<std::endl;
        return 0;
    }

    二,const object(常量对象):如果不希望某个对象的值被修改,则定义该对象的时候可以在前面添加const关键字。

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A():a(0){}
        void setNum() 
        {
            a++;//这条语句存在与否程序都不能通过编译
        }
    private:
        int a;
    };
    
    int main()
    {
        const A a;
        a.setNum();
        return 0;
    }
    //[Error] passing 'const A' as 'this' argument of 'void A::setNum()' discards qualifiers [-fpermissive]

    结论:非静态成员函数通过this来操作const A类型对象a的值。这是不符合定义的(因为这样是允许修改对象的)。所以const对象不能调用非静态成员函数,即使它什么都不做。

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A(){}
        static void setNum() 
        {
            a++;
        }
    private:
        static int a;
    };
    int A::a=0;
    
    int main()
    {
        const A a;
        a.setNum();
        return 0;
    }

    结论:const对象能调用静态成员函数,尽管他修改一些静态成员变量。

    三,const member function(常量成员函数):在常量成员函数执行期间不应该修改其所作用的对象。

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A():a(0){}
        void read() const
        {
            //a++;  //const成员函数不修改非静态成员变量 
            b++;
        }
    private:
        int a;
        static int b;
    };
    int A::b=0;
    
    int main()
    {
        A a;
        a.read();
        return 0;
    }

    结论  1,常量成员函数不能修改成员变量的值。(静态成员变量除外);

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A():a(0){}
        static int getNum(){ return b; }
        void setNum(){a=1;}
        void read() const
        {
            //setNum();   //[Error] passing 'const A' as 'this' argument of 'void A::setNum()' discards qualifiers [-fpermissive]
            getNum();
        }
    private:
        int a;
        static int b;
    };
    int A::b=0;
    
    int main()
    {
        A a;
        a.read();
    }

    结论 2,常量成员函数不能调用同类的非常量成员函数(静态成员函数除外);

    这样我们又想起上面的const对象不能调用普通成员函数,但是通过学习了const成员函数我们知道const对象可以调用const成员函数。

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A():a(0){}
        void setNum() const{}
    private:
        int a;
    };
    
    int main()
    {
        const A a;
        a.setNum();
        return 0;
    }

    常量成员函数重载:两个函数如果名字参数都相同,但是一个是const,一个不是,算作重载。

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A():a(0){}
        int read() const
        {
            return a;
        }
        int read()
        {
            a++;
            return a;
        }
    private:
        int a;
    };
    
    int main()
    {
        const A a1;//调用const成员函数
        A a2;     //调用非const成员函数
        cout<<"a1 read return:"<<a1.read()<<endl;
        cout<<"a2 read return:"<<a2.read()<<endl;
        return 0;
    }

     

    四,常引用:引用前面加上const关键字,成为常引用,不能通过常引用修改其引用的值。
      对象作为参数是,函数调用是对象会调用复制构造函数,效率低。用指针作为参数,代码又不好看 --》传引用
      直接传引用有时有缺陷:当我们不希望相应对象改变的时候,此时很可能此函数修改了对象。这不是我们想要的。
      所以我们就可以使用对象的常引用作为参数:既提高了效率,也不修改对象。

    class A{
    ...
    };
    void compare(const A& a)
    {
    ...
    }

    五,最后提一下函数调用方式。
    看看以下两个不同调用的区别。

    A a;
    A* p = &a;
    a.getNum();
    p->getNum();

    c++支持三种类型的成员函数:static,nonstatic,virtual。三种成员函数的调用都有不同。
    补充:static 成员函数不可能做到的两点:1,不可以操作nonstatic成员;2,不能声明为const。
    1,static成员不依赖对象,nonstatic依赖对象,所以static成员函数不能调用nonstatic成员,但是nonstatic成员函数可以调用static成员;
    2,不存在static和const同时修饰的成员函数,因为普通成员函数里面隐含一个指向类对象的this指针存在,同样const修饰的成员函数也隐含一个const this指针来保证该函数不修改类对象。
    但是static成员函数不接受this指针的,由于两者相违背,所以不存在。

    nonstatic成员函数

    class A
    {
    public:
        A():val(0){}
        int getNum(){return val;}
    private:
        int val;        
    };
    
    int main()
    {
        A a;
        A* p = &a;
        a.getNum();
        p->getNum();
        return 0;
    }

    上面两种调用成员函数的区别:
    首先实际上成员函数已经做了一些转化:安插了一个额外的参数(this指针)到形参列表,然后对非静态数据成员的操作变为了经由this来指针操作了。

    int getNum(A* const this)  //若是const成员函数 则为 const A* const this
    {
        return this->val;
    }

    所以上述的a.getNum()的调用变成了  getNum(&a);  p->getNum()的调用变成了  getNum(p);

    上面的this指针不可以改变指向但是可以改变指向的对象,而const this指针则既不可以改变指向,也不可以改变指向的对象   --》所以const成员函数可以操作const对象。

    虚函数:
    如果上述的函数getNum()是虚函数调用又变了:(由于虚函数表)
    p->getNum()将会内部转化为  (*p->vptr[1])(p)   //vptr是指向虚函数表的指针,然后通过索引获得虚函数的地址,而后解引用调用虚函数。函数形参列表里面的p表示this指针
    a.getNum() 将会内部转化为  (*a.vptr[1])(&a)

    静态成员函数:
    对于static member function来说,a.getNum()和p->getNum()将被转换为一般的nonmember函数调用。

     参考:北京大学MOOC《程序设计实习》

        《深度探索c++对象模型》

  • 相关阅读:
    执行.class文件
    Ant能干什么,编译?打包!
    C的随想
    微服务
    2018年宝鸡市高考复课报告会材料
    用图像解不等式
    高频易错题目01
    2018年宝鸡市二检数学题目解答
    点差法
    和事件的概率求法
  • 原文地址:https://www.cnblogs.com/jlxuexijidi-2015/p/5353109.html
Copyright © 2020-2023  润新知