本文是《侯捷C++面向对象高级编程》的重点总结笔记系列之——参数传递与返回值。博主会一周至少更新两篇文章,主要是总结每节课程的精华并启发思考。适合有一些基础的C++小白一起学习,慢慢地细细咀嚼,跟着一起思考必能有一些收获,如能带来任何一点点收获,那么期待您的三连~ 刚入门的小伙伴也可以先关注或收藏一波,待日后再看。阅读过程若有疑问,欢迎一起讨论!
在正式开始今天这篇总结之前,我们需要明白this指针是什么?熟悉的朋友可自行跳过第一节。
目录
this指针
this指针实际上是成员函数的一个形参,成员函数由此获得了调用对象的信息。在对象调用成员函数时,会自动将对象的地址作为实参传递给 this指针。 而不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到成员函数的参数列表中。
this 作为隐式形参,本质上是成员函数的局部变量,所以只能用在成员函数的内部,并且只有在通过对象调用成员函数时才给 this 赋值。成员函数最终被编译成与对象无关的普通函数,除了成员变量,会丢失所有信息,所以编译时要在成员函数中添加一个额外的参数,把当前对象的首地址传入,以此来关联成员函数和成员变量。这个额外的参数,实际上就是 this,它是成员函数和成员变量关联的桥梁。
const成员函数
成员函数该加const的地方一定要加,因为当调用者定义了一个类对象为const类型后(注意图中标黄部分),再调用成员函数时(如调用real方法时),若发现成员函数没有声明为const,会出现如下错误:error: 'this' argument to member function 'real' has type 'const complex', but function is not marked const。
结合this指针的概念,想一想这是为什么呢?在我们的例子中, c1 是一个const 对象, 它调用了 real 方法,所以函数签名(即函数调用的本质形式)应该是:real(&c1){};对于成员函数没有声明为const的情况,函数签名为:real(complex* this){},即我们默认的 this 指针并不是 const 类型;而 c1是一个 const 对象, 即应该为:real(const complex* this){}。所以参数类型不匹配, 编译无法通过!
这下我们明白了, const 修饰成员函数, 根本上是修饰了 this 指针,进而修饰了类对象。因此也造就了它的写法与众不同(在参数列表之后)。
参数传递与返回值
首先,抛出一个结论:参数传递尽量传引用,不希望被改值就const引用。返回值也尽量用引用。那么,有哪些注意事项呢?
参数传递
参数传引用的好处:底层实现是指针,传指针通常比较快(能避免拷贝带来的开销);当然,当传字符等较小字节参数时,也可传值(想一想这是为什么?)。
我们知道,指针的大小根据机器字长来决定。也就是,即便是64位的计算机,传引用的参数类型大小也只是8字节。当我们的参数类型是类或结构体时,其效率提升显著。
观察上图,细心的你一定又会发现一个疑问。一般情况下,我们的数据成员是private类型,只有对象内部能直接访问自己的成员,而不能通过其他对象直接访问其他对象的成员。而上图标黄部分却在c2对象的函数内部访问了c1的数据成员。这是因为相同类的各个对象互为友元,即相同类的各个对象都能直接访问对方的成员。
返回值
当返回值使用引用类型时,返回值不能是函数内部创建的变量。这是因为在函数内部创建的变量都属于函数作用域的局部变量,离开函数作用域时,变量所占内存的值被销毁。因此,若返回的是局部变量,则外部变量接收到的是已经被销毁的内存空间的值。
总结
第一,数据一定放在private里头;第二,参数尽可能的是以reference来传。要不要加const?看情况;第三,返回值也尽量以reference来传。能不能?万一不行呢?但是首先你得先告诉自己,我先考虑用reference引用来传,可不可以?;第四,在函数在类的本体里头的这些函数应该加const就要加。如果不加,可能使用者去用的时候编译器会报错,会埋怨你,因为你就是class的设计者,你设计的不好;第五,构造函数,有一个特殊的语法叫initialization list,单冒号的那一行,那个要尽量去用它。