C中的static关键字在人们发明"重载"这个概念之前实际上已经被重载了,而C++则为static增添了新的含义。
在C和C++中,static都具备两个基本语意,不幸的是,两者经常混杂在一起。
1.在固定地址空间分配内存,而不是每次函数调用时在栈上分配空间。这里static的意味是静态存储(static storage)。
2.只对一个特定的转换单元(translation unit)可见。这里static的意味是内部链接(internal linkage)。
函数中的static变量
若程序员不为static局部变量提供初始化值,编译器会保证该对象被初始化为0(对于内置类型)。
函数中的static对象
默认初始化为0只对内置类型有意义,对于static类对象,必须由构造函数完成初始化。
静态对象的析构
静态对象(不仅限于局部静态变量)在程序从main()函数推出时被自动调用析构函数。
如果调用标准库函数abort()结束程序的话,静态对象的析构函数是不会被自动调用的。
需要理解的是,只有已经被创建的对象才被析构。具体的说,一个包含局部静态对象的函数若从未被调用过的话,该类对象的析构函数自然不会在推出main()时被调用,因为该对象根本还不曾存在过!
链接控制
使用内部链接(internal linkage)的优点之一在于可以在将标识符的定义放置在头文件中,而不用担心链接时会出现名字冲突的问题。
C++中通常放置于头文件中的名字定义,如const,默认具有internal linkage属性。
当用于局部变量时,static不再具有可见性的含义,而只是改变变量的存储方式。
名字空间
namespace关键字的唯一目的是创建名字空间
创建名字空间时需要注意的:
1。名字空间的定义只能出现在全局范围,或者是在另一个名字空间的内部
2。名字空间定义的结尾处不需要加分号。
3。一个名字空间的定义可在多个文件中完成。
4。一个名字空间可以定义为另一个名字空间的alias。
匿名名字空间
匿名名字空间中的名字在其所在的转换单元中自动可见,不用加限定符。
编译器保证每个转换单元(translation unit)中最多只有一个匿名名字空间。
匿名名字空间中的名字虽然对于外部TU是不可见的,但其链接属性仍是external linkage。
C++废弃了使用static来设置internal linkage的方法,而推荐使用匿名名字空间。
友元与名字空间
若在类定义中声明友元的话,该友元自动被插入类所属的名字空间。 例如:
namespace Me {
class Us {
//...
friend void you();
};
}
现在函数you()是名字空间Me的一员了。
使用名字空间
可以通过三种方式来使用某个名字空间内的名字
1。显式使用范围限定符::。
2。使用using directive,将某个名字空间内的名字全部引入当前名字空间。
3。使用using declaration,一次引入一个名字。
using和namespace关键字一起使用时被称为using directive。
using declaration被视为在当前范围内的声明,而using directive被视为对当前范围全局性的声明;因此,using declaration可能会覆盖using directive引入的名字。
using declaration只是引入了名字,并没有包含类型信息;
using directive的有效性只到那个文件的编译器为止。
实际上,using directive 通常出现在.cpp文件而不是在头文件中,因为这样做会污染全局名字空间。
C++中的静态成员
类中的静态成员必须在类定义之外被定义(但是在类定义中同样要进行声明),并且只允许被定义一次,因此,这样的静态成员的定义一般放在类的实现部分(.cpp),而不是定义部分(.h)。
初始化:对于static const的整型变量可以在类中进行定义,对所有其它情况,必须在类外完成定义。
局部类不允许拥有静态成员变量。
在C和C++中,static都具备两个基本语意,不幸的是,两者经常混杂在一起。
1.在固定地址空间分配内存,而不是每次函数调用时在栈上分配空间。这里static的意味是静态存储(static storage)。
2.只对一个特定的转换单元(translation unit)可见。这里static的意味是内部链接(internal linkage)。
函数中的static变量
若程序员不为static局部变量提供初始化值,编译器会保证该对象被初始化为0(对于内置类型)。
函数中的static对象
默认初始化为0只对内置类型有意义,对于static类对象,必须由构造函数完成初始化。
静态对象的析构
静态对象(不仅限于局部静态变量)在程序从main()函数推出时被自动调用析构函数。
如果调用标准库函数abort()结束程序的话,静态对象的析构函数是不会被自动调用的。
需要理解的是,只有已经被创建的对象才被析构。具体的说,一个包含局部静态对象的函数若从未被调用过的话,该类对象的析构函数自然不会在推出main()时被调用,因为该对象根本还不曾存在过!
链接控制
使用内部链接(internal linkage)的优点之一在于可以在将标识符的定义放置在头文件中,而不用担心链接时会出现名字冲突的问题。
C++中通常放置于头文件中的名字定义,如const,默认具有internal linkage属性。
当用于局部变量时,static不再具有可见性的含义,而只是改变变量的存储方式。
名字空间
namespace关键字的唯一目的是创建名字空间
创建名字空间时需要注意的:
1。名字空间的定义只能出现在全局范围,或者是在另一个名字空间的内部
2。名字空间定义的结尾处不需要加分号。
3。一个名字空间的定义可在多个文件中完成。
4。一个名字空间可以定义为另一个名字空间的alias。
匿名名字空间
匿名名字空间中的名字在其所在的转换单元中自动可见,不用加限定符。
编译器保证每个转换单元(translation unit)中最多只有一个匿名名字空间。
匿名名字空间中的名字虽然对于外部TU是不可见的,但其链接属性仍是external linkage。
C++废弃了使用static来设置internal linkage的方法,而推荐使用匿名名字空间。
友元与名字空间
若在类定义中声明友元的话,该友元自动被插入类所属的名字空间。 例如:
namespace Me {
class Us {
//...
friend void you();
};
}
现在函数you()是名字空间Me的一员了。
使用名字空间
可以通过三种方式来使用某个名字空间内的名字
1。显式使用范围限定符::。
2。使用using directive,将某个名字空间内的名字全部引入当前名字空间。
3。使用using declaration,一次引入一个名字。
using和namespace关键字一起使用时被称为using directive。
using declaration被视为在当前范围内的声明,而using directive被视为对当前范围全局性的声明;因此,using declaration可能会覆盖using directive引入的名字。
using declaration只是引入了名字,并没有包含类型信息;
using directive的有效性只到那个文件的编译器为止。
实际上,using directive 通常出现在.cpp文件而不是在头文件中,因为这样做会污染全局名字空间。
C++中的静态成员
类中的静态成员必须在类定义之外被定义(但是在类定义中同样要进行声明),并且只允许被定义一次,因此,这样的静态成员的定义一般放在类的实现部分(.cpp),而不是定义部分(.h)。
初始化:对于static const的整型变量可以在类中进行定义,对所有其它情况,必须在类外完成定义。
局部类不允许拥有静态成员变量。
静态成员函数:静态成员函数只能访问静态成员变量,无法访问非静态成员变量,也不发调用非静态成员函数。这是因为静态成员函数在调用时没有this指针被传递
静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用 类成员函数指针来储存。举例如下:
class base{
static int func1();
int func2();
};
int (*pf1)()=&base::func1;//普通的函数指针
int (base::*pf2)()=&base::func2;//成员函数指针
静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。
静态成员函数不可以同时声明为 virtual、const、volatile函数。举例如下:
class base{
virtual static void func1();//错误
static void func2() const;//错误
static void func3() volatile;//错误
};
最后要说的一点是,静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。