1 常量成员函数(const member functions)
class Complex {
public:
Complex(double r = 0, double i = 0)
:re(r), im(i) {}
Complex(double r) :re(r), im(0) {}
Complex& operator += (const Complex&);
double real() const /*常量成员函数*/ { return re; }
double imag() const /*常量成员函数*/ { return im; }
private:
double re, im;
friend Complex& __doapl(Complex, const Complex&);
}
常量成员函数的形式就是在函数的小括号后面加 const。在C++里面,类中的成员函数大致又可以分为两种,会改变数据的和不改变数据的,不改变数据的也叫只读函数,不改变数据的函数要加上const。
下面有两段调用函数的代码,如果 real() 函数不加const,第一段代码的调用没有问题,但在第二段,当对象被设置为const类型时,再调用real() 函数,编译器就会报错。因为函数不加const,代表该函数有可能改变数据,而常量对象代表对象中的数据是不能改变的,这时候常量对象如果调用了会改变数据的函数就会发生冲突,所以编译器通不过。
Complex c1(2, 1);
cout << c1.real();
cout << c1.imag();
const Complex c1(2, 1);
cout << c1.real();
cout << c1.imag();
2 参数传递:pass by value vs. pass by reference(to const)
上图中标黄的部分就是参数。参数传递有两种,一种是值传递,实际上将获得实参的副本,并将它压入函数栈,也就是说函数内修改的是实参的副本,是不会影响实参的。另一种是引用传递,只传地址,这样传递的内容很小,所以很快。引用的底层就是用指针来实现的。一个良好的编程习惯就是参数传递尽量传引用。 当传引用的时候,在函数内部是可以通过引用来修改对象的数据的,如果只是为了获取对象的数据,而不进行修改,可以在参数的类型的前边加const,意思是不能通过引用更改传进来对象的数据,只能获取到数据。
本质上来说,当形参是指针类型时,也算是按值传递,传递的是指针变量的副本,但这个副本可以影响指针指向的对象。
3 返回值传递:return by value vs. return by reference(to const)
返回值的传递也尽量使用引用传递。注意,尽量不是全部,只是在可以的情况下,要传引用。那么在什么情况下不能传引用呢,如果某一个对象是在函数内部创建的,它的作用域就是该函数,函数结束对象也就被清空了,这个时候如果返回该对象的引用,通过引用找不到该对象,所以这种情况下不能返回引用。当然如果将该对象声明为static,这样即使函数结束,对象也存在。
4 友元函数
类的友元函数是定义在类外部,但有权访问类的所有private成员和protected成员。尽管友元函数的原型在类的定义中出现过,但友元函数并不是成员函数。如果声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字friend。如下所示
由于友元函数打破了函数的封装特性,当友元函数太多的时候也不太好。
相同class的各个对象互为友元。如下图所示
5 总结
- 类中数据成员一定要放在private下
- 参数尽可能传引用,是否加const,需要看情况
- 返回值也尽量传引用
- 在类的成员函数中,应该加const的,就要加。如果不加,使用者在用的时候可能会报错
- 构造函数要使用初始化列表进行赋初值
主要参考:
1 面向对象高级开发—侯捷老师