随侯捷老师的课程学习C++面向对象。
第一部分是complex类的编写,老师通过例子培养标准大气的编程习惯,总结如下:
1.类定义的防卫
在头文件中用 #ifndef xxx #define xxx #endif 包住整个类定义部分,作为一个“防卫”方法。防止client多次include我们编写类的头文件。
2.public和private
类中我们不希望外界直接访问,仅想要类内访问的放到private里面,一般包括所有的变量。大部分函数(接口)放到public供外界访问。
3.函数声明
声明一个函数时要思考几个方面:
(1)参数。每一个参数,优先考虑使用引用的方式提高效率。 引用在C++的内部实现其实就是指向变量的指针常量(T* const),即指针不可变,但指向的值可以变化。因此引用传递(地址传递)通常比值传递效率更高。其次考虑函数中是否会改变该参数,不希望改变就加const。 假如不加const,编译器会认为该函数会改变此参数,这时若我们传入const常量,会报错。
(2)返回值。优先考虑用引用接收。 此处需要判断,若返回的值是函数内新创建的,则函数结束后该值生命周期结束,其引用也没有意义,因此此时必须用值传递的方式接收。若希望返回值不可修改,可加const。
(3)函数本身。只有类的非静态成员函数可以加const,即若该成员函数不改变类内成员变量,函数名后加const,为readonly,除非该变量被mutable修饰。此外,对于简单的函数,希望实现为inline。
4.运算符重载
类的运算符重载有两种实现方式。
(1)类内成员函数。作为类内成员函数时,有一个隐含的参数this,就是该类本身。运算就是将右参数加(减乘除等)到左参数(this)上。
(2)类外函数。
考虑函数返回值时需要考虑用户连续使用运算符的情况。
5.模板类和友元函数
模板类在类定义前加template<typename T>,函数实现时前面也要加template<typename T>。
友元函数作为类外函数,但可以访问类内成员变量,可以在类内进行定义。
6.遇到的问题
(1)cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
原因是构造函数传入参数为非const引用。
complex(T& r = 0, T& i = 0) : re(r), im(i) {}
在以下代码创建complex对象时,传入的参数为临时计算结果,是常量。常量无法作为非const引用类型的参数传入,因此报出以上错误。原因是编译器认为函数会改变r和i的值,而不允许参数r和i为常数(const)。
template<typename T>
inline complex<T>
operator + (const complex<T>& x, const complex<T>& y)
{
return complex<T>(real(x) + real(y), imag(x) + imag(y));
}
解决方法是将构造函数改为:
complex(T r = 0, T i = 0) : re(r), im(i) {}
或:
complex(const T& r = 0, const T& i = 0) : re(r), im(i) {}
(2)friend declaration … declares a non-template function
原因是友元函数声明的问题。将在类内的声明:
friend complex<T>& __doapl(complex<T>*, const complex<T>&);
改为:
template<typename U>
friend complex<U>& __doapl(complex<U>*, const complex<U>&);
可以解决问题。