C++规范
.h文件书写(侯捷第二讲)
文件引入
include< .h>包含的是库文件。
include “ .h”包含的是自己写的文件
关于全局变量
头文件可以放什么?
- struct/union 的声明,C++可以在头文件的 struct/class 内部随即给出方法的实现
- typedef 声明
- 函数,类声明
- extern 变量声明
- 一些const常量
绝对不能放 - 全局定义变量(声明都不要有,全局变量声明就是定义)
- 给出函数的定义(可以有声明,若非要在.h文件给出定义则需要结合extern预防重定义)
1 |
|
1 |
|
1 |
以上代码会有函数重定义报错,把a.h的函数声明留下,把定义搬到a.cpp就好了。
否则重定义教你做人。
C语言在头文件中包含全局变量有三种形式:
- 在头文件中声明(extern)一个全局变量,在一个C文件中定义全局变量,然后在所有的引用了这个头文件的C文件里都可以使用该全局变量值。
如在main.c定义 int a = 3;
然后定义一个main.h,那么所有引用main.h的c文件中,均可以访问a并更改其值。 - 在头文件中定义一个静态全局变量。那么所有引用该头文件的C文件,均拥有一个作用域在本文件范围内的同名静态全局变量。不同文件中的该变量虽然同名,但却是不同的变量。可以这样防止重命名冲突
比如在a.h中定义:
static int a = 3;
那么在a.c中引用a.h,并将a值修改为4。
在b.c中也引用a.h,不对a值做修改,打印a值,仍为3, 不会因为a.c中的修改而改变值,这是因为有static生成内部链接,让全局变量a/函数的作用域变小了,即使加extern也无法被其他文件调用。 - 在头文件中定义全局变量。该头文件仅可以被一个C文件引用一次。
比如a.h中定义
int a = 3;
在a.c中可以引用a.h,并对a进行访问和修改。
如果在同项目下有b.c引用了a.h,编译器在链接时会报同名全局变量的错误,导致编译失败。
头文件中的防卫式声明
1 |
|
函数名是operator +=,函数调用后返回一个别名,这里定义一个complex c1(2,1);complex c2(3,4);c1 += c2;最后返回给c1。任何成员函数都有一个this point,谁调用成员函数这个this就指向谁。注意this是用complex&接收的,而与 this相同类型的临时变量value不能用complex&接收,因为value会在函数执行完毕后被释放掉。
注意
需要注意的是上面返回了一个别名。但如果最终的重载运算结果不存储在二元操作数之中,需要临时存储,比如7+c1,那么重载运算就要放到class body之外,可以这样写:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29complex operator + (const complex& c1, const complex& c2)
{
return complex(c1.real()+c2.real(), c1.imag+c2.imag())
}
```
  这里用到了临时对象typename(),省掉了命名(这也不是构造函数)。其中typename也可以是int,double等。这行代码执行完毕后空间被释放掉。
##
```c++
complex conj (const complex& x)
{
return complex (x.real(), x,imag());
}
ostream& operator <<(ostream& os,const complex& x)
{
return os<<'('<< x.real()<<','<<x.imag()<<')';
}
```
  返回ostream&是为了应对cout<< c1 << conj(c2);的情况。
  为什么conj()返回的临时对象可以被operator <<的别名接收?conj()运行完不是清理内存了吗?这是因为c++的内存清理机制是惰性的,它并不会在此函数调用完立即清除其占用的内存,return的临时对象编译器会保留一下,此时这个临时对象是有实际的地址,因此可以传给operator <<函数中的别名类型,执行到下一行,也就是cout结束后才把conj()之中临时对象的内存释放掉。
# 类中的this
上个大类中
```c++
complex c1,c2,c3;
cout<<c1.real();
cout<<c2.real();
用c语言这么写:1
2
3complex c1,c2,c3;
cout<< complex::real(&c1);
cout<< complex::real(&c2);
这个real函数:1
2
3
4
5
6
7
8class complex
{
public:
double real() const
{ return this->re; }//this->可写可不写,编译器会帮忙补齐的。
provate:
double re, im;
}
因此在调用类中的函数时,编译器会把this指针指向调用函数的对象。
类中的静态变量
创建一个银行账户的大类,创建的每个对象都是存款人,这些存款人在银行中有相同的利率。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Account
{
public:
static double m_rate;//声明
static void set_rate(const double& x) {m_rate = x}
}
double Account::m_rate = 8.0;//定义
int main()
{
Account::set_rate(5.0);
Account a;
a.set_rate(7.0);
}
类中的静态成员变量
类中的静态成员变量与类中的成员变量不同,无论创建多少个类的对象,静态成员都只有一份
类中的静态函数
静态函数和一般的成员函数一样也只有一份。成员函数都是默认有this指针的,而静态成员函数没有this指针,因此它只能操作静态成员变量。
也就是说你没有创建任何对象时,你也可以使用静态成员变量和静态函数,比如银行现在没有人来存钱,就不用创建对象,可以通过设置静态变量来先设定利率。这样以后即使10000个人创建对象,你也可以通过调整静态变量实时更改利率。如果把利率放在成员变量中,挨个更改每个已创建对象的利率是一个极其麻烦的过程!