1) auto
auto变量就是局部变量,一般不用加auto。自动的意思是自动作用域,自动离开作用域。
2) register
register变量是提示编译器尽量放在寄存器中保存,以增加
速度。
l 只能定义局部的register变量,或者作为函数参数,没有全局或静态的。
l 在C语言中,是不能对register变量取地址的,因为它没有虚地址,在寄存器里。而C++中,它是可以取址的,这时,C++编译器不会把它放到寄存器里。
l 一般不建议使用register,相信编译器能够做的更好。
3) volatile
l volatile变量
告诉编译器,别对这个变量做任何优化,因为它随时都会改变。
比如,多线程中,共同访问一个变量,如果编译器对其优化(放在寄存器中是优化的一种),第二次读时可能直接读寄存器中的值,而另外一个线程(或中断)改了变量,结果读出来的值是旧的。
它和const/register是类相反的,const是告诉编译器这是不可改变的,可以优化。而register直接告诉编译器将变量存入寄存器中。
用法:
volatile int a;
l volatile函数
int i = 0;
void Func1 volatile()
{
if ( i == 10 )
{
//操作
}
}
这可以告诉编译器,别对函数里的变量访问进行优化,因为这些变量有可能被多线程或者中断服务程序改变。
4) static
l 函数里static变量只能在本函数里可见
l 全局的static变量只能在本文件中可见,当然,如果是头文件,可以include进去,然后也是可见的。
l 它比全局变量好的原因是,不容易被错误的改变,因为它限制了变量的可见性(见上)
l 任何时候用非const的static变量时都需要注意线程安全问题
l 内部类型的static默认初始化为0,自定义类static对象默认调用默认构造函数初始化
l 所有全局的变量都是存储在静态存储区,和static唯一不同的是它是内部链接的
关于链接方式,请参考
http://blog.csdn.net/yeming81/archive/2010/05/31/5637704.aspx
l 全局或静态对象的构造函数发生在进入main()之前
l 静态成员的初始化
非const的static成员的初始化只能在类外初始化;
const非static成员只能在构造函数初始化列表初始化;
const static成员初始化可以在声明时或类外初始化;
class A
{
public:
A():e(1.7f), d(1.6f) //error,static属于静态区,必须在构造
函数前初始化
{
printf("%f/n",a);
}
private:
static int a;
static const int b = 10;
static const float c;
static const float d;
const float e;
const float f;
static const int intArray[];
};
int A::a = 1;
const float A::c = 2.1f;
// static const float A::c = 3.1f;// error
const int A::intArray[] = {1, 3, 5};
const float A::f = 1.2f; //error, only static
l 局部类不能含有static成员
l static成员函数不能是virtual的
因为,虚函数是需要对象来判断类型,从而获得函数的地址(VPTR是存在对象中的)。静态的成员函数是没有this指针的。
virtual void Func(this, int a)
{
}
p->Func(1); //利用p (this)指针找到VPTR,然后得到真正函数的地址。
l static变量与对象大小
class B
{
public:
B(){}
const static long a = 10; //常量
const static long b = 10;
const static long c = 10;
static long d; //静态区
const long e; //只有这个变量占空间
};
sizeof (B) = 4;
l 类static函数的好处
1. 限制全局函数在类里
2. static函数不能访问成员变量,所以无需带this指针参数,提高效率
5) const
l C中,const是只读的变量,不是常量;C++中它是常量。区别用例子描述如下:
const int MAX = 10;
char buffer[MAX]; //C中它是不合法的,
可以用enum或 define替代;
//C++中它是合法的。
l C中const变量分配在全局静态区;C++中则在常量区,编译过程中值就定了。
l C++编译器并不为const变量创建存储空间,而是保存在符号表里。如果用extern介入外部链接或者取const变量的地址,编译器必须要分配空间。
1) 普通const 变量
const int i = 10;
const int j = i+20; //常量折叠,即编译期间将i代入
int* p = &i; //取址导致内存分配
char buffer[i]; //尽管内存分配,i还是进入了符号表
2) const 数组
const int intArray [] = {1, 3, 5, 7};
char buffer[intArray[1]]; //编译错误
由于数组过于复杂,编译器不把它放入符号表,而是分配内存区保存。编译期间不会知道具体值。
l const指针
² 指向的内容是const的
以下两者写法皆可:
const int* a;
int const* a;
² 指针本身是const的
int* const a;
² 两者都是const的
以下两种写法皆可:
int const* const a;
const int* const a;
l const 字符串陷阱
char* p = “hello”; //这时,”hello”是常量,p指针是一个指向常量的指针
所以,严格的写法应该是 const char* p = “hello”。
如果,p[0] = ‘a’;则程序运行崩溃,因为试图去更改常量区,行为是未定义的。
如果想要改变一个数组,需要这样定义:
char p[] = “hello”; //注意 char [] p = “hello”是错误的!
“hello”将保存在全局静态区,而不是常量区,p指向首地址。
l const参数与返回值
² 按值传递的const参数
void Func( const int i )
{
i = 10; //目的就是防止在程序里改变临时变量
i,对于用户而言是没//有影响的
}
所以,按值传递的const可以这样写,这样用户接口更简单。
void Func( int i )
{
const int& j = i;
}
² 按值返回的const – 防止返回值被赋值
按值返回内置类型
int Func1() { return 29; }
Func1() = 20; //编译器就阻止了这个操作,因为返回的是一个值(字面值),而不是变量。
const int Func2() { return 29; } 所以,内置类型const返回值没有必要!
按值返回自定义类型(struct,class等)
class A
{
public:
void modify(){ a = 10; };
private:
int a;
};
A Func1() { return A(); }
Func1() = A(); //合法,产生一个临时的非
const A对象
Func1().modify(); //合法,非const A对象
可以更改数据
const A Func2() { return A(); }
Func2() = A(); //不合法
Func2().modify(); 不合法
void Func3( A& a) {}
Func3( Func2() ); //不合法,因为不能
从const变成一个非const的引用
l 类里的const
² const数据成员
class A
{
public:
A(): i (10) //必须在这初始化因为这是没有调用构 造之前唯一可行的地方
{
i = 10; //错误,不能二次初始化const。
第一次也不能在这里
}
private:
const int i = 10; //不能在这里初始化
static const int j = 11; //这是合法的,且只能在这里初始化,因为:
//类里的static表示类中只有一份,在类中任何//构造函数之前就必须存在,这是编译期间常
//量,保存在符号表里
};
² const函数成员
类的const对象只能调用const函数;
在函数的声明和定义都必须注明是const的!!!
例子如下:
int A::Func() const {};
在函数内部不能改变变量值。
² const函数成员与mutable
如果在const函数里想改变某个变量,可将变量声明为mutable,
mutable int i;
这种方法是用来替换老的野蛮法:
(A*)this ->i++; //将当前const指针转成非const指针,然后更改。
注意:这时候,const称为是按逻辑const,
通常的const是按位const。
l const 对象对性能的提升
一个const能够放进ROM只读存取器,系统访问ROM是比RAM快的。
能放进ROM的条件必须满足:
² 按位const
也就是类里不能存在const方法访问mutable变量,允许有非const方法。
² class或struct不能有用户自定义的构造函数或析构函数,也不能包含有用户自定义的构造函数或析构函数的对象。
² 不能有基类
因为需要初始化基类。