static限定符
static local variable
- 静态局部变量的特点是”一次构造,永不析构,直到程序结束“。因此静态局部变量可以用来保值,这和全局变量行为相似)
- 静态变量放在全局变量区
void func() { static int i = 0; cout << i++ << endl; } int main() { for (int i = 0; i < 10; i++) { func() } }
static function
- 函数前用
static
修饰,表示此函数为本文件专用,其他文件无法进行访问。 - 函数默认是全局域,全局变量默认是文件域。
static
可将函数默认的全局域改为文件域
//a.cpp static void function() { //....... } //b.cpp void function(); int main() { function(); //报错!!! return 0; }
函数默认是全局域,全局变量默认是文件域,这也就说明为什么我们在使用外部变量(定义在其他文件的变量)前需要用
extern
进行声明,而使用外部函数是不需要(当然也是可以的)
static data member
- 类中可以定义静态变量,一次性初始化,所有对象共享。
- 类中的静态变量,既可以通过对象访问,也可以通过类名访问。
- 静态变量必须在类外进行初始化,而且只能初始化一次。
- 不能在构造函数中为静态变量赋值。
class Static { public: static int i; int j; Static(int j) { this->j = j; } }; int Static::i = 1; int main() { Static s1(1), s2(2); cout << s1.i <<s2.i << endl; }
static function member
- 类中的静态函数,既可以通过对象访问,也可以通过类名访问
- 静态函数中没有this指针
- 静态函数只能访问类中的静态变量,不能访问类的对象。
class Static { public: static void print() { cout << "static!" << endl; } } int main() { //通过对象调用 Static s; s.print(); //通过类名调用 Static::print(); }
设计模式:单例模式(
signleton
)
单例模式是指某个类全局只有一个对象,一个单例模式的例子如下——
class Single { static Single* self //定义一个指向该类唯一对象的指针 Single(); //构造函数私有化 public: static Single* get_instance(); } Single* Single::self = NULL; Single* Single::get_instance() { //获取这一对象 if (self == NULL) { self = new Single(); } return self; } int main() { Single* p = Single::get_instance(); return 0; }
const限定符
const parameter
- 函数参数定义为const,
则只能使用该参数的值,不能改变该参数,也不能将该参数作为左值(
l-value
)使用。
void func(const int *p) { (*p)++; //error! 不能将(*p)作为左值使用,因为p指向的是const int }
const data member
- 在类中我们将数据成员定义为
const
,这样的数据成员只读。 - 对于
const
数据成员来说,初始化主要有以下两种方法——- 使用类内初始值
- 使用构造函数的初始化列表
如果同时使用以上两种方式,则已初始化列表中的值为最终初始化结果
- 不能在构造函数和其他成员函数内部对
const
数据成员进行赋值!
class Student{ const int id; };
早期C++中没有const data member这种语法,党史如果要在类中定义常量,一般需要用枚举型
enum
。
const function member
- 一般来说,
const
对象是不可以调用函数的,这是为了防止函数会修改const
对象中的值。但是如果真的需要其调用函数怎么办(前提是被调用的函数不能修改对象的值)? - 我们可以将被调用的函数用
const
来限定,这样就可以让const
对象调用该函数了。写法如下——
class Student{ public: void fun() const; //const限定符写在最后 } void Student::fun() const { cout << "const function mumber!" << endl; } int main() { const Student s; s.func(); //可以进行调用 }
关于new和delete
new
和malloc
都可以用于动态申请堆空间来建立新对象。但是,new
一个对象时会调用该类的构造函数,而malloc
不会。因此,new
和malloc
有以下关系——
\[new = malloc + construction\]- 同理,
delete
和free
也有相似的关系。(注意:destruction
应该在free
前面)
\[delete = destruction + free\]
运算符重载
一般情况下, +
, -
, *
,
++
,
[]
等运算符只能作用于基本类型,不能作用于对象。但是,我们可以在类中对这些运算符进行重载,这样我们就可以将运算符应用于对象了。重载运算符的写法如下——
[返回值类型] operator [运算符]( 形参表) {
}
下面以
+
,
++
两个运算符为例,介绍一下具体的写法——class Account {
int balance;
char *name;
public:
Account(int balance);
void save(int money);
//重载运算符,返回自身的引用
Account& operator + (int money);
Account& operator ++; //前++
Accoutn operator ++ (int); //后+++
};
Account::Account(int balance) {
this->balance = balance;
}
void Account::save(int money) {
this->balance += money;
}
//重载运算符+
Account& Account::operator + (int money) {
this->save(money);
return this;
}
//重载运算符++*(前自加)
Account& Account::operator ++ {
this->balance++;
return this;
}
//重载运算符++*(后自加)
Account Account::operator ++ (int) {
Account early = *this;
this->balance++;
return early;
}
++
这个运算符比较玄学,因为既可以前自加,还可以后自加。前自加我们可以直接使用Object& operator ++{}
来进行定义。后自加为了与之区分,使用了一个int
作为占位参数,
即使用Object& operator ++(int) {}
来进行定义(注意只能是int
,不能是char
或者其他)。
注意在后自加的函数定义中,有一句是Account early = *this;
,这句话实际上是通过传值来进行拷贝,会默认调用一个
拷贝构造(在上一节课的笔记中讲过)。本来,这种写法是不推荐的,但是,为了配合后自加"先返回原值,再自加"这一变态的要求,我们又不得不这样写……
作业:使用SQLite,实现一个借书、还书的流程。
ORMapping