一,引用:某个变量的引用等价于这个变量,是这个变量的一个别名。
#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++对象模型》