??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
使用const的好处在于它允许指定一U语意上的约?-----某种对象不能被修?-------~译器具体来?/span>
施这U约束。通过constQ你可以通知~译器和其他E序员某个D保持不变。只要是q种情况Q你p
明确C用const Q因样做可以借助~译器的帮助保q种U束不被破坏?/span>
Q一Q?/span>
首先解释一下const与指针的关系Q?/span>
const在指针的声明中有一下三UŞ式:
const char *p = "hello"; // 非const指针,
// const数据Q就是说p指向的那个内存空间的数据是不?/span>
变的Q但pq可以指向新的内存地址?/span>
char * const p = "hello"; // const指针,
// 非const数据Q就是说q个指针p一旦赋值或初始化,?/span>
不能在指向其他位|了Q但其指向的位置的数据值是可变的?/span>
const char * const p = "hello"; // const指针,
// const数据Q这个就很明显了Q集上述两家之长处(?/span>
可能是短处哦Q)Q上qC者都不可变?/span>
一般来_你可以在头脑里画一条垂直线I过指针声明中的星号Q?Q位|,如果const出现在线的左边,
指针指向的数据ؓ帔RQ如果const出现在线的右边,指针本n为常量;如果const在线的两辚w出现Q二
者都是常量?/span>
恩,差点忘了Q还有一UŞ式:
char const * p = "hello";
q其实与上边的情形一是一LQ只是由于个Z惯的不同Q二者都是对的?/span>
Q二Q?/span>
在一个函数声明中Qconst可以指的是函数的q回|或某个参敎ͼ对于成员函数Q还可以指的是整个函
数?/span>
constQ?Q?int fun(int constQ?Q?amp; )constQ?Q?/span>
{
int temp;
retrun temp;
}
参数?const属性(上例2处)一般用引用传递,是ؓ了保证该参数在函C不允许被修改Q一旦修改,
~译器会报错?/span>
而返回值的const属性(上例1处)是保证函数的q回g被修改,也许你会质疑q种可能性,但是q种?/span>
能性确实存在,
详细情Ş如下Q(摘自effective c++Q?/span>
const rational operator*(const rational& lhs,
const rational& rhs);
很多E序员第一眼看到它会纳PZ么operator*的返回结果是一个const对象Q因为如果不是这P?/span>
户就可以做下面这L坏事Q?/span>
rational a, b, c;
...
(a * b) = c; // 对a*b的结果赋?/span>
我不知道Z么有些程序员会想到对两个数的q算l果直接赋|但我却知道:如果aQb和c是固定类?/span>
Q这样做昄是不合法的。一个好的用戯定义cd的特征是Q它会避免那U没道理的与固定cd不兼?/span>
的行为。对我来_对两个数的运结果赋值是非常没道理的。声明operator*的返回gؓconst可以防止
q种情况Q所以这样做才是正确的?/span>
呵呵Q象Scott Meyersq样的大师见地就是不一般吧
接下来说明函数的const属性:Q上?处)
当然喽,一般用于成员函CQ它有以下属性:
Q?Qconst成员函数不被允许修改它所在对象的M一个数据成员?/span>
Q?Qconst成员函数能够讉K对象的const成员Q而其他成员函C可以?/span>
Q三Q尽量?const代替define 吧,因ؓconst是类型安全的?/span>
应该使用
const double pi = 3.1415926;
而不要用#define pi 3.1415926
后者是宏,仅仅是对E序中的pi?.1415926代替Q会让你对于一些编译时的错误很隑֮位?/span>
]]>
]]>
【导诅R介lC++引用的基本概念,通过详细的应用分析与说明Q对引用q行全面、透彻地阐q?
引用是C++引入的新语言Ҏ,是C++常用的一个重要内容之一Q正、灵zd使用引用Q可以ɽE序z、高效?br>
引用?br>
引用是某一变量Q目标)的一个别名,对引用的操作与对变量直接操作完全一栗?br>
引用的声明方法:cd标识W?&引用?目标变量名;
【例1】:int a; int &ra=a; //定义引用ra,它是变量a的引用,卛_?br>
说明Q?br>
Q?Q?amp;在此不是求地址q算Q而是h识作用?br>
Q?Q类型标识符是指目标变量的类型?br>
Q?Q声明引用时Q必d时对其进行初始化?br>
Q?Q引用声明完毕后Q相当于目标变量名有两个名称Q即该目标原名称和引用名Q且不能再把该引用名作ؓ其他变量名的别名?br>
ra=1; {h?a=1;
Q?Q声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本w不是一U数据类型,因此引用本n不占存储单元Q系l也不给引用分配存储单元。故Q对引用求地址Q就是对目标变量求地址?amp;ra?amp;a相等?br>
Q?Q不能徏立数l的引用。因为数l是一个由若干个元素所l成的集合,所以无法徏立一个数l的别名?br>
引用应用
1、引用作为参?
引用的一个重要作用就是作为函数的参数。以前的C语言中函数参C递是g递,如果有大块数据作为参C递的时候,采用的方案往往是指针,因ؓq样可以避免整块数据全部压栈,可以提高E序的效率。但是现在(C++中)又增加了一U同h效率的选择Q在某些Ҏ情况下又是必ȝ选择Q,是引用?br>
【例2】:
void swap(int &p1, int &p2) //此处函数的Ş参p1, p2都是引用
{ int p; p=p1; p1=p2; p2=p; }
为在E序中调用该函数Q则相应的主调函数的调用点处Q直接以变量作ؓ实参q行调用卛_Q而不需要实参变量有M的特D要求。如Q对应上面定义的swap函数Q相应的主调函数可写为:
main( )
{
int a,b;
cin>>a>>b; //输入a,b两变量的?br>
swap(a,b); //直接以变量a和b作ؓ实参调用swap函数
cout<<a<< ' ' <<b; //输出l果
}
上述E序q行Ӟ如果输入数据10 20q回车后Q则输出l果?0 10?br>
由【例2】可看出Q?br>
Q?Q传递引用给函数与传递指针的效果是一L。这Ӟ被调函数的Ş参就成ؓ原来主调函数中的实参变量或对象的一个别名来使用Q所以在被调函数中对形参变量的操作就是对其相应的目标对象Q在主调函数中)的操作?br>
Q?Q用引用传递函数的参数Q在内存中ƈ没有产生实参的副本,它是直接对实参操作;而用一般变量传递函数的参数Q当发生函数调用Ӟ需要给形参分配存储单元QŞ参变量是实参变量的副本;如果传递的是对象,q将调用拯构造函数。因此,当参C递的数据较大Ӟ用引用比用一般变量传递参数的效率和所占空间都好?br>
Q?Q用指针作为函数的参数虽然也能辑ֈ与用引用的效果Q但是,在被调函C同样要给形参分配存储单元Q且需要重复?*指针变量?的Ş式进行运,q很Ҏ产生错误且程序的阅读性较差;另一斚wQ在主调函数的调用点处,必须用变量的地址作ؓ实参。而引用更Ҏ使用Q更清晰?br>
如果既要利用引用提高E序的效率,又要保护传递给函数的数据不在函C被改变,应使用常引用?br>
2、常引用
常引用声明方式:const cd标识W?&引用?目标变量名;
用这U方式声明的引用Q不能通过引用对目标变量的D行修?从而引用的目标成为constQ达C引用的安全性?br>
【例3】:
int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确
q不光是让代码更健壮Q也有些其它斚w的需要?br>
【例4】:假设有如下函数声明:
string foo( );
void bar(string & s);
那么下面的表辑ּ是非法的:
bar(foo( ));
bar("hello world");
原因在于foo( )?hello world"串都会生一个时对象,而在C++中,q些临时对象都是constcd的。因此上面的表达式就是试囑ְ一个constcd的对象{换ؓ非constcdQ这是非法的?br>
引用型参数应该在能被定义为const的情况下Q尽量定义ؓconst ?br>
3、引用作回?br>
要以引用q回函数|则函数定义时要按以下格式Q?br>
cd标识W?&函数名(形参列表及类型说明)
{函数体}
说明Q?br>
Q?Q以引用q回函数|定义函数旉要在函数名前?amp;
Q?Q用引用
q回一个函数值的最大好处是Q在内存中不产生被返回值的副本?br>
【例5】以下程序中定义了一个普通的函数fn1Q它用返回值的Ҏq回函数|Q另外一个函数fn2Q它以引用的Ҏq回函数倹{?br>
引用作ؓq回|必须遵守以下规则Q?br>
Q?Q不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用成Z"无所?的引用,E序会进入未知状态?
Q?Q不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这U情况(q回函数内部new分配内存的引用)Q又面其它尬局面。例如,被函数返回的引用只是作ؓ一个时变量出玎ͼ而没有被赋予一个实际的变量Q那么这个引用所指向的空_由new分配Q就无法释放Q造成memory leak?br>
Q?Q可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某U业务规则(business ruleQ相兌的时候,其赋值常怸某些其它属性或者对象的状态有养I因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针)Q那么对该属性的单纯赋值就会破坏业务规则的完整性?br>
Q?Q引用与一些操作符的重载:
操作符<<?gt;>Q这两个操作W常常希望被q箋使用Q例如:cout << "hello" << endl; 因此q两个操作符的返回值应该是一个仍然支持这两个操作W的引用。可选的其它Ҏ包括Q返回一个流对象和返回一个流对象指针。但是对于返回一个流对象Q程序必重斎ͼ拯Q构造一个新的流对象Q也是_q箋的两?lt;<操作W实际上是针对不同对象的Q这无法让h接受。对于返回一个流指针则不能连l?lt;<操作W。因此,q回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许q就是C++语言中引入引用这个概늚原因吧?赋值操作符=。这个操作符象流操作W一P是可以连l用的Q例如:x = j = 10;或?x=10)=100;赋值操作符的返回值必L一个左|以便可以被l赋倹{因此引用成了这个操作符的惟一q回值选择?br>
【例6?试用返回引用的函数gD辑ּ的左倹{?br>
Q?Q在另外的一些操作符中,却千万不能返回引用:+-*/ 四则q算W。它们不能返回引用,Effective C++[1]的Item23详细的讨Zq个问题。主要原因是q四个操作符没有side effectQ因此,它们必须构造一个对象作回|可选的Ҏ包括Q返回一个对象、返回一个局部变量的引用Q返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作ؓq回值的三个规则Q第2?两个Ҏ都被否决了。静态对象的引用又因?(a+b) == (c+d))会永qؓtrue而导致错误。所以可选的只剩下返回一个对象了?br>
4、引用和多?
引用是除指针外另一个可以生多态效果的手段。这意味着Q一个基cȝ引用可以指向它的zcd例?br>
【例7】:
class A;
class BQpublic A{……};
B b;
A &Ref = b; // 用派生类对象初始化基cd象的引用
Ref 只能用来讉Kzcd象中从基cȝ承下来的成员Q是基类引用指向zcR如果AcM定义有虚函数Qƈ且在BcM重写了这个虚函数Q就可以通过Ref产生多态效果?br>
引用ȝ
Q?Q在引用的用中Q单U给某个变量取个别名是毫无意义的Q引用的目的主要用于在函数参C递中Q解军_块数据或对象的传递效率和I间不如意的问题?br>
Q?Q用引用传递函数的参数Q能保证参数传递中不生副本,提高传递的效率Q且通过const的用,保证了引用传递的安全性?br>
Q?Q引用与指针的区别是Q指针通过某个指针变量指向一个对象后Q对它所指向的变量间接操作。程序中使用指针Q程序的可读性差Q而引用本w就是目标变量的别名Q对引用的操作就是对目标变量的操作?br>
Q?Q用引用的时机。流操作W?lt;<?gt;>、赋值操作符=的返回倹{拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用?/font>
new用法:
1. 开辟单变量地址I间
1)new int; //开辟一个存放数l的存储I间,q回一个指向该存储I间的地址.int *a = new int 即ؓ一个intcd的地址赋值给整型指针a.
2)int *a = new int(5) 作用同上,但是同时整数赋gؓ5
2. 开辟数l空?/p>
一l? int *a = new int[100];开辟一个大ؓ100的整型数l空?/p>
二维: int **a = new int[5][6]
三维及其以上:依此cL.
一般用? new cd [初值]
delete用法:
1. int *a = new int;
delete a; //释放单个int的空?/p>
2.int *a = new int[5];
delete [] a; //释放int数组I间
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];
q算Wnew比malloc要简单多了,q是因ؓnew内置?/span>sizeof、类型{换和cd安全查功能。对于非内部数据cd的对象而言Q?/span>new在创建动态对象的同时完成了初始化工作。如果对象有多个构造函敎ͼ那么new的语句也可以有多UŞ式。例?/span>
class Obj
{
public :
Obj(void); // 无参数的构造函?span>
Obj(int x); // 带一个参数的构造函?span>
…
}
void Test(void)
{
Obj *a = new Obj;
Obj *b = new Obj(1); // 初gؓ1
…
delete a;
delete b;
}
如果?span>new创徏对象数组Q那么只能用对象的无参数构造函数。例?span>
Obj *objects = new Obj[100]; // 创徏100个动态对?span>
不能写成
Obj *objects = new Obj[100](1);// 创徏100个动态对象的同时赋初?span>1
在用delete释放对象数组Ӟ留意不要丢了W号‘[]’。例?span>
delete []objects; // 正确的用?span>
delete objects; // 错误的用?span>
后者相当于delete objects[0]Q漏掉了另外99个对象?br>
malloc 和free只是分配了空_
而new和delete不仅分配了空_q完成了Ҏ造函数和析购函数的调用,当然q是对对象而言?
两者在对基本数据类型操作时候,没有多大区别Q区别在于对对象q行操作时。malloc和free是函?但new和delete是操作符
using namespace std;
void display_bits(unsigned u)
{
int t;
for(t = 128; t >= 1; t /= 2)\
{
if(u&t) cout<<"1 ";
else cout<<"0 ";
}
cout<<endl;
}
int main()
{
display_bits(10);
return 0;
}
stu_average(a);
subject_average(a);
return 0;
}
void stu_average(int (*p)[6])
{
int sum=0;
int i,j;
for (i=0;i<n;i++)
{
cout<<*(*(p+i)+0)<<" ";
for (sum=0,j=1;j<6;j++)
{
sum+=*(*(p+i)+j);
cout<<setiosflags(ios::fixed)<<setprecision(1);
cout<<*(*(p+i)+j)<<" ";
}
cout<<sum/5.0<<endl;
}
}
void subject_average(int (*p)[6])
{
int i,j;
int sum=0;
for (j=1;j<6;j++)
{
for (i=0,sum=0;i<n;i++)
{
sum+=*(*(p+i)+j);
}
cout<<setiosflags(ios::fixed)<<setprecision(1);
cout<<(float)sum/n<<" ";
}
cout<<endl;
}
谁能l我讲一下里面的指针哦?Q?Q?