Inside Class
对象和类的关系
对象表示物体、概念、事件等具体的内容;类表示某些性质、操作的集合,是抽象的内容。
类和对象的关系,就像 C++ 中的类型和变量。
重载函数
在 C++ 中,函数名和参数类型决定一个函数。所以,同一个名字的函数,可以有不同参数的版本,在调用时会根据名字和传入的参数决定具体执行的代码。
void print(char *s);
void print(char *s, int width);
print("Hello");
print("Hello", 3);
同样,类中的成员函数也可以重载。
构造函数
我们可以根据参数,调用不同的构造函数:
class sorted{
public:
sorted(){}
sorted(int _x){
x = _x > 0? _x: 10;
}
sorted(int _x, int _z){
x = _x > 0? _x: 10;
z = _z > 0 && _z < x? _z: 1;
}
sorted(int _x, int _y, int _z){
x = _x > 0? _x: 10;
z = _z > 0 && _z < x? _z: 1;
y = _y < x && _y > z? _y: 5;
}
private:
int x, y, z;
};
代理构造
不难发现,上文的构造函数中,出现了许多的重复代码 x = _x > 0? _x: 10;
,这并不利于维护。
代理构造 Delegating Constructor 可以在构造函数中调用另一个构造函数,来实现减少重复代码的效果。
上文可以改造成这样:
class sorted{
public:
sorted(){}
sorted(int _x){
x = _x > 0? _x: 10;
}
sorted(int _x, int _z): sorted(_x){
z = _z > 0 && _z < x? _z: 1;
}
sorted(int _x, int _y, int _z): sorted(_x, _z){
y = _y < x && _y > z? _y: 5;
}
private:
int x, y, z;
};
缺省参数
在 C++ 中,可以为函数的参数填写默认值,这样可以在调用的时候省略一些参数。
规则:参数的缺省值要从右边开始连续声明,有缺省值的参数右侧不能出现无缺省值的参数;调用函数时,传入的参数从左边开始填入,缺少的参数使用缺省值。
int err_query(int x = 1, int y, int k = 0); // Error
int query(int x, int y, int k = 0, int p = 1, int l = 1, int r = 0x3f3f3f3f);
int ans1 = query(1, 3); // query(1, 3, 0, 1, 1, 0x3f3f3f3f)
int ans2 = query(1, 3, 2); // query(1, 3, 2, 1, 1, 0x3f3f3f3f)
int ans3 = query(1, 3, 1, 1, 100);
注意,在函数声明处声明缺省值,在实现处不能再声明。
此例中的缺省参数,相当于声明了 query(x, y)
、query(x, y, k)
、query(x, y, k, p)
等函数。
内联函数
函数的调用,实际上是对系统栈进行操作:
- 放入参数
- 放入返回对象的地址
- 计算
- 算出返回对象的值
- 把所有放入的内容弹出
而内联函数类似 C 语言的宏定义,将调用该函数的地方展开成函数的代码,通过增加代码长度来减小时间开销。
内联函数的函数体是它的原型,而不是实现。
展开之后,函数本身可能在 .obj
文件中不存在,只在调用处出现函数体。所以,我们可以(也应该)把内联函数放在头文件里,而不必担心重复实现的问题。
inline
关键字用于声明内联函数。当然,像已经弃用的 register
一样,它只作为提示符,实际上是否内联取决于编译器对函数的考量(大函数更不容易内联)。
在函数的声明和定义处,都需要 inline
关键字。
inline void plusOne(int x);
inline void plusOne(int x){return x + 1;}
对于类的成员函数,如果在类的声明中就定义了函数,那么这个函数会自动内联。
当然,也可以把内联函数放在类的声明后面,但是要确保放在头文件里,避免连接时没有函数,导致调用出现错误。