C++标准库复数类complex解析(观看侯捷老师视频总结)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ModestBean/article/details/79592468

说在开始

最近用了两天时间在侯捷老师的带领下学习了C++标准库中的复数类complex,收获真的巨多。其中涉及许多C++的知识点和细节,包括构造函数初始化的写法、const的用法,变量作用域的使用、友元函数、内联函数、运算符的重载、如何提高C++代码的执行效率、如何提高自己的C++类的的通用性等等自己掌握了很多C++的细节和面向对象的知识。讲的真的好,不愧是C++的专家。所有代码都可以在我的github上找到https://github.com/ModestBean/C-Samples 如果有错误还希望大家指出。

——————-2018-3-19更新————————-

在写着两个类的过程中,遇到了无法正常编译的问题,自己无法解决,在C++交流群中询问问题。发现了自己的两大错误。

  1. 不应当将有关的编译语句写到.h文件中,.h只是用来声明,头文件是没有编译的,在其中放入编译语句当然无法编译成功。在头文件中一般不放全局函数的实现代码,除非是inline/static。但是侯捷老师将自己的全局函数的代码都写到了.h文件中,侯捷老师列举的方法都是inline的。可能是为了讲课方便吧。
  2. 楼主的工程由两个编译单元(.cpp),都包含里complex.h,所以两个编译单元里面都有一份operator <<函数的实现,链接的时候因为重名而失败了…。这也是我编译错误的另一个原因。我同时在两个编译单元complex.cpp和main.cpp中存在相同的内容,将complex.cpp移出工程后,正常编译。

再一次感觉到C++的细节呀。

—————————————————————————–

代码部分

comple.cpp

#ifndef COMPLEX_H
#define COMPLEX_H
#include <iostream>
using namespace std;
class complex
{
public:
    complex(double r = 0, double i = 0) :re(r), im(i) {};
    complex& operator += (const complex&);
    double real() const { return re; }
    double imag() const { return im; }
private:
    double re, im;
    friend complex&  _doapl(complex*, const complex&);
};
inline complex&
_doapl(complex* ths, const complex& r) {
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}
inline complex&
complex::operator += (const complex& r) {
    return _doapl(this, r);
}
inline double
imag(const complex& x)
{
    return x.imag();
}
inline double
real(const complex& x)
{
    return x.real();
}
ostream&
operator << (ostream& os, const complex& x)
{
    return os << '(' << real(x) << ',' << imag(x) << ')';
}
#endif

main.cpp

#include "complex.h"
int main() {
    complex c1(2, 1);
    complex c2(5);
    c2 += c1;
    cout << c2;
    cin.get();
}

听课笔记

定义部分
1. 在头文件中防御式常数定义
2. class的head,在body里面开始做动作
3. 数据应当放在private里面,实部和虚部
4. 对外发表的函数应当放在public当中,构造函数要不要默认值,参数值考虑是pass by value还是pass by reference
5. 构造函数的初始列,将实部虚部设置为初始值
6. 考量构造函数还需要做什么事情。也就是{}括号中的内容
7. 设计复数类应该支持什么样的能力,这里设计了+=的能力。函数有两种选择:成员函数和非成员函数。
8. 设计一个取得其private成员的public函数。函数的类型需要考虑要不要加const,如果函数当中不会改变data的时候应该使用const,这里只是取出实部和虚部,所以这里加上了const
9. 定义一个friend函数,因为要直接取得复数类的私有成员。
函数的实现
10. 因为属于class里面的,所以操作符的重载需要写成complex:: operator +=类型的。
11. 然后思考这个函数的参数是什么,成员函数中的参数都会有一个隐藏的this指针,这个this指针会优先传递成员函数中。对于不在修改的参数应该加上const。
12. 考虑成员函数的返回内容,最好传递reference,如果传递出去的东西不是local object,尽量去传递reference
13. 考虑函数是不是可以变成inline函数,能不能成为内联函数不知道,只有编译器才可以做出最终的决定。
14. 加的动作不是本身成员函数中去做的,而是交给另一个函数去做的。
15. 另外附属一些动作都可以设计为非成员函数,也就是全局函数。为什么不把+这个动作设计成成员函数呢 ?需要注意的是,复数不仅可以+复数,也可以加float,int,如果只把+这个动作放到class中,只能完成复数与复数的相加
16. 左边的参数+右边的参数   会生成一个local的对象,这时候函数不能在传递引用。当函数执行完毕后,对应的对象也会销毁,这里应当提起重视。应该return by value。
17. 这里有一个新的语法。class的名称加上小括号。例如:complex();此就是创建了一个临时的object。
特殊的操作符重载 <<
18. 因为要输出复数的形式,简单的<<操作符无法达到要求了,在C++标准库当中对此操作符<<进行重载。
19. 操作符重载有两种方式:成员函数和非成员函数 。
20. 使用者可能使用连串的输出cout<<c1<<endl,如果return by value 就会出现错误,此时应该使用return by reference

我的笔记描述的可能没有那么准确,大家自己观看侯捷老师的视频吧。如果想要资源可以加我的微信qq619192323

猜你喜欢

转载自blog.csdn.net/ModestBean/article/details/79592468