总结一下C++中几个关键字的用法,只是总结,不做什么分析。我觉得要真正理解的话必须知道C++的内存模型。
被昨天的电话面试弄得好郁闷啊……抓紧时间学习!
据说看一个人代码中const用了多少就初步看出一个人的C++水平,所以我理解就是要尽量多用const。
1. 修饰常量
最基本的用法,用const修饰一个变量,表示这是一个常量,这种用法可以代替C语言里面的宏定义。注意要在声明时初始化,如果是类的数据成员,则
在构造函数的初始化列表中初始化。
int
a
=
999
;
//
定义了常量a,代替宏定义
//
const int b;
//
错误,常量定义时要初始化
extern
const
int
c;
//
外部定义的常量不用初始化了
int
const
d
=
0
;
//
与const int等价,写法习惯不同而已
const
long
e
=
0
;
//
同理,把int换成char、long、类是一样的
class
Cls
{
public
:
Cls(
int
a,
int
b):_a(a)
//
常数成员要在初始化列表初始化
{
_b
=
b;
}
private
:
const
int
_a;
int
_b;
}
;
2. 修饰引用,指针
对一个常量的引用或指针要用常指针,也就是不能修改所引用、指向的变量。如果不使用常引用、指针,则须用const_cast<>进行
转换。指向字符char的常指针经常用来表示字符串,像windows中的LPCSTR就是const char *。
int
&
g
=
a;
//
a的内容不能改,所
以g(a的引用)也是const
//
int &h=a;
//
错误
int
&
i
=
const_cast
<
int
&>
(a);
//
使用const_cast<>()把常量转成非常量
int
const
&
j
=
a;
//
与
const int &等价,写法习惯不同而已
const
int
*
k
=&
a;
//
a的内容不能改,所以k(a的指针)也是const
int
const
*
l
=&
a;
//
与const int *等价,写法习惯不同而已
//
int *m=&a;
//
错误
const
char
*
n
=
"
string
"
;
//
字符串“string”内部字符不能改变了
char
*
o
=
"
string2
"
;
//
字符串“string2”可以修改
3. 修饰对象
如果修饰的是一个对象,则表示该对象的数据成员均为常量,并且只能调用该对象的常成员函数,这一点在后面解释。综合1、2、3条得出,const修
饰符表示所修饰的内存区域被上了锁,不能修改。对一个对象的常引用经常用来函数传参,当函数参数为对象是,直接按值传参会调用对象拷贝构造函数,复制对
象,对程序效率造成影响,所以一般按引用传参,为了不改变传入的参数,要加const表示是常引用。
Cls f(
1
,
2
);
//
这个f的_b也不可改变了
void
func(
const
Cls
&
arg)
{
//
这种传参方式代替直接按值传Cls
}
4. 另外一种const修饰指针的方法
也就是著名的const char *和char * const的区别的问题。const char
*前面说过,意思是常指针,char*所指的内存区域不能被修改,用来表示字符串。而char *
const的意思指针所指向的位置不能修改,也就是该指针不能指向其他内存区域了,这和引用很像,char * const相当于char
&,所以常引用const char &相当于const char *
const,也就是指针指向谁不可变,指针指向的内容也不可变。注意const是写在了*的前面还是后面,这是唯一区别,char const
*的意思和const char *是一样的。
char
*
n
=
"
string
"
;
//
字符串“string”内部字符不能改变了,但可以让n指向其他字符串
char
*
o
=
"
string2
"
;
//
字符串“string2”可以修改
char
*
const
p
=
o;
//
p不能指向其他字符串,但指向的内容可以更改,理解为p是o的引用
const
char
*
const
q
=
n;
//
n是常字符串,所以要用常引用
5. 修饰成员函数
在一个类的成员函数的参数表后面加上const,表示这是一个常函数,这个函数不会修改该对象数据成员的内容,这个函数也不能调用普通的成员函数,
只能调用常函数。其实,常函数是指隐式传入的this指针是个常指针。这种写法可以让编译器帮助我们避免一些错误发生。另外,一个被const修饰的对
象,只能调用它的常函数。
Cls
{
public
:
Cls(
int
a,
int
b,
const
char
*
c):_a(a),_c(c)
{
_b
=
b;
}
void
foo()
{
_b
=
123
;
}
void
foo2()
const
{
//
下面两句都会编译错误
//
_b=234;
//
foo();
}
public
:
const
int
_a;
int
_b;
const
char
*
_c;
}
;
const
Cls f(
1
,
2
,
"
hello
"
);
//
这个f的_b不可改变了
void
main()
{
Cls cls(
2
,
3
,
"
world
"
);
cls._b
=
1
;
//
f._b=1;
//
错误
//
f.foo();
//
错误,不能调用非
const函数
}
C++里面可以定义const成员函数的; 它的作用是防止修改成员变量,
比如那些只是输出信息的函数可以定义成const成员函数,
常成员函数
使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常量或常对象,没有使用const关键字说明的成员函数不能用
来操作常对象。常成员函数说明格式如下:
<类型说明符> <函数名> (<参数表>) const;
其中,const是加在函数说明后面的类型修饰符,它是函数类型的一个组成部分,因此,在函数实现部分也要带const关键字。下面举一例子说明常成员函
数的特征。
#include
class R
{
public:
R(int r1, int r2) { R1=r1; R2=r2; }
void print();
void print() const;
private:
int R1, R2;
};
void R::print()
{
cout< }
void R::print() const
{
cout< }
void main()
{
R a(5, 4);
a.print();
const R b(20, 52);
b.print();
}
该例子的输出结果为:
5,4
20;52
该程序的类声明了两个成员函数,其类型是不同的(其实就是重载成员函数)。有带const修饰符的成员函数处理const常量,这也体现出函数重载的
特点。
类中的const成员函数
通常,程序中任何试图修改const 对象的动作都会被标记为编译错误
const char blank = ' ';
blank = '/n'; // 错误
但是,程序通常不直接修改类对象。在必须修改类的对象时,是调用公有成员函数
集来完成。为尊重类对象的常量性,编译器必须区分不安全与安全的成员函数,即区分试图
修改类对象与不试图修改类对象的函数。例如
const Screen blankScreen;
blankScreen.display(); // 读类对象
blankScreen.set( '*' ); // 错误: 修改类对象
类的设计者通过把成员函数声明为const 以表明它们不修改类对象。例如
class Screen {
public:
char get() const { return _screen[_cursor]; }
// ...
}
只有被声明为const 的成员函数才能被一个const 类对象调用。关键字const
被放在成员函数的参数表和函数体之间。对于在类体之外定义的const 成员函数,我们必须在它的定义和声明中同时指定关键字const。
把一个修改类数据成员的函数声明为const 是非法的。
一般来说,任何一个类如果期望被广泛使用,就应该把那些不修改类数据成员的成员函数声明为const 成员函数。但是把一个成员函数声明为const
并不能阻止程序员可能做到的所有修改动作。把一个成员函数声明为const
,可以保证这个成员函数不修改类的数据成员。但是如果该类含有指针,那么在const
成员函数中就能修改指针所指的对象,编译器不会把这种修改检测为错误,
这
常常令C++初学者吃惊