C++基础

林爱琦 / 2023-08-03 / 原文

Talk is cheap. Show me the code. 
C++分为C++语言和C++标准库

 





版本演化可分为C++98(1.0) , C++11(2.0) , C++14
话不多说,上代码
头文件命名方式,例如complex.h
首先要写防卫式声明,以前写的时候只是知道要写,现在知道才叫什么。
1 #ifndef _MYCOMPLEX_
2 #define _MYCOMPLEX_
3 
4 . . .
5 
6 #endif
然后写你要声明的类

类声明

 1 class complex
 2 {
 3 public:
 4   complex (double r = 0, double i = 0)//尝试改成传引用,得是大的,类似string
 5   : re (r), im (i) 
 6   { }//在里面开文件,申请内存什么的
 7 
 8   complex& operator += (const complex&);//成员函数
 9 
10   double real () const { return re; }//注意const
11   double imag () const { return im; }
12 private:
13   double re, im;
14 
15   friend complex& __doapl (complex *, const complex&);
16 
17 };

 complex是名称,然后写成员变量re im,注意设置私有访问级别,12 13行。

考虑函数是成员函数还是非成员函数

写成员函数,设置访问级别为公用访问级别,构造函数为4 5 6行,第四行可以传引用,例如在传字符串的时候使用,在一些情况下必须使用初始化列表,例如需要初始化const修饰的类成员,花括号里面以后可以放一些其他操作,例如打开文件

8 9 10行是成员函数,8行是操作符重载,使用了this指针,其中用const指明传入值不可改变,9 10行的const要注意不可改变返回值,注意返回值尽量设置为reference,意思是先考虑返回renference,实在不行再用value.

15行是友元friend,表示此函数可以自由取得private成员

1 inline complex&
2 complex::operator += (const complex& r)
3 {
4   return __doapl (this, r);
5 }

这里this指针回自行调用,写函数时先写名称,注意格式,再写参数,reference还是value,返回值是什么形式,最后是内部操作

1 inline complex&
2 __doapl (complex* ths, const complex& r)
3 {
4   ths->re += r.re;
5   ths->im += r.im;
6   return *ths;
7 }

inline表示内联,是对编译器的一种建议,至于编译器接受不接受不一定,内联函数不要太大,没有循环体。

注意return的是指针,接收的是reference,此为传入者无需知道接收者是以reference形式接收

 写C++文件,命名complex.cpp

 1 #include <iostream>
 2 #include "complex.h"
 3 
 4 using namespace std;
 5 
 6 ostream&
 7 operator << (ostream& os, const complex& x)
 8 {
 9   return os << '(' << x.real () << ',' << x.imag () << ')';
10 }
11 
12 int main()
13 {
14   complex c1(2, 1);
15   complex c2(4, 0);
16   cout << (c1 += c2) << endl;
17   return 0;
18 }

1 2行是对头文件进行包含,4行是对命名空间的包含,此为标准库,6 7 8 9 10行是对操作符号的重载,cout属于ostream类,必须要有返回值,因为涉及连续传输操作

执行结果为

1 (6,1)

 

上面所说的是Complex class,下面讲述 String class,区别在于后者有指针,需要三大函数(Big Three)

先写头文件string.h,写入防卫式声明

然后写类,命名String

 1 class String
 2 {
 3 public:                                 
 4    String(const char* cstr=0);                     
 5    String(const String& str);                    
 6    String& operator=(const String& str);         
 7    ~String();                                    
 8    char* get_c_str() const { return m_data; }
 9 private:
10    char* m_data;
11 };

考虑成员变量,设置private,字符串用指针比用数组更合适,涉及动态分配内存

考虑成员函数,设置public,4行为构造函数,5行为拷贝构造函数,6行为拷贝复制,7行为析构函数,5 6 7行函数被称为三大函数

构造函数负责申请空间,存储字符串,而析构函数负责删除字符串,回收空间

 1 inline
 2 String::String(const char* cstr)
 3 {
 4    if (cstr) {
 5       m_data = new char[strlen(cstr)+1];
 6       strcpy(m_data, cstr);
 7    }
 8    else {   
 9       m_data = new char[1];
10       *m_data = '\0';
11    }
12 }
13 
14 inline
15 String::~String()
16 {
17    delete[] m_data;
18 }

拷贝构造:没有存在一个字符串,需要创建一个再把一个字符串复制过来

1 inline
2 String::String(const String& str)
3 {
4    m_data = new char[ strlen(str.m_data) + 1 ];
5    strcpy(m_data, str.m_data);
6 }

输入值为字符串的reference,无返回值,4行使用new申请内存空间,5行调用strcpy函数复制,属于深拷贝

使用strcpy,必须包含它的头文件

1 #include <cstring>

拷贝构造使用方法

1   String s3(s2);

拷贝复制:存在两个字符串,把其中一个字符串复制到另一个字符串里

 1 inline
 2 String& String::operator=(const String& str)
 3 {
 4    if (this == &str)
 5       return *this;
 6 
 7    delete[] m_data;
 8    m_data = new char[ strlen(str.m_data) + 1 ];
 9    strcpy(m_data, str.m_data);
10    return *this;
11 }

属于操作符重载,输入值为右值字符串的reference,输出值为字符串的reference,4 5行为检测自我赋值(处理或排除一些特殊情况,例如自我赋值,为空,超出范围等等)

采用this指针代表左值,7行,删除左值,也就是清除左值内容,释放左值内存,8 9行为拷贝构造内容,返回this指针

假设不写’检测自我赋值‘这两行代码,那么你将要复制的右值和你想要赋值的左值为同一空间,在执行删除左值时,将直接删除你的右值,程序虽不会报错,但会输出错误(不信你就试试)

1   s3 = s1;

写的string_test.cpp如下

 1 #include "string.h"
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 ostream& operator<<(ostream& os, const String& str)
 7 {
 8    os << str.get_c_str();
 9    return os;
10 }
11 
12 int main()
13 {
14   String s1("hello"); 
15   String s2("world");
16     
17   String s3(s2);
18   cout << s3 << endl;
19   s3 = s1;
20   s1 = s1;
21   cout << s3 << s2 << endl;     
22   cout << s2 << endl;  
23   cout << s1 << endl;      
24 }

输出结果如下

1 world
2 helloworld
3 world
4 hello