引用和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++对象模型》

posted on 2016-04-04 22:05  延长比赛  阅读(424)  评论(0编辑  收藏  举报

导航