??xml version="1.0" encoding="utf-8" standalone="yes"?>
2.const修饰指针
W一U情况:const int *ptr=&a; ptr为指向常量的指针Q其所指的g可修改,但是其所指向的地址可以修改?/span>
W二U情况:int * const ptr=&aQ?/span>ptr为常量指针,其所指的地址不可被修改,但是其所指的值可以被修改?/span>
W三U情况:const int * const ptr=&aQ?/span>ptr为指向常量的帔R指针Q其所指向的地址不可修改Q其所指向的g不可修改?/span>
实例Q?br>3.const 用于函数参数
直接看实例:
4.const 对于c?/span>
{1}对于const 修饰的类成员变量Q只能在构造函数的参数初始化表里对其进行初始化Q否则会引v~译错误?/span>
Q?/span>2Q对?/span>const 修饰的成员函?/span> Q如 int FunQ?/span>int aQ?/span>constQ这样声明之后Q何企囑֜函数内部修改成员变量的值或者调用非const成员函数都会引v~译错误?/span>
Q?/span>3Q对?/span>const声明的用戯定义cȝ对象Q如果调用这个类的非const成员函数Q将会引L译错误,~译器会保证?/span>const对象的生命期内不被改变?/span>
如果const对象一定要调用此函数的话,那就此函数声明?/span>const?br>实例Q?br>
/*******************************************************************************
* SGI*STL是STL之父Alexander Stepanov和STL巨匠Matt Austern{h的作? 是当?nbsp; *
* 最富盛名、最的STL实现版本Q全部源代码和说明文档可?a href="http://www.sgi.com/STL/?>www.sgi.com/STL/?/font> *
* ? 是我们学习STL的最佌? 但是众所周知, STL使用了大量复杂艰qC++Ҏ? *
* 加上STL本n的复杂和庞大, 使得阅读代码本n成Z仉常困隄工作. 以下?nbsp; *
* 字是我在学习STLq程中得到的一些经验和猜测, 希望能对大家有所帮助, 更希望能 *
* 得到大家的批评和指正, 以利于我们的共同提高. *
* myan *
*******************************************************************************/
在SGI*STL源代码里, typenameq个新的C++关键字得使用可以说是随处可见. 很多以前学习q?br>C++的h可能q不认识typename, 其实它的常规用法很简? 在声明模板函数或者模板类?
传统的写?
template <class T>
generic_function() {
//........
}
亦可以写?br>template <typename T>
------------
generic_func() {
//...............
}
引入q个关键字主要是Z避免class可能lh带来的?
本来typename的用法就是这么简? 但是STL源代码中q有typename的一U不常见的用? 如果
不了? 阅读源代码时׃遇到困难. 因ؓ目前我找不到有关q个问题的说? 所以自p验了
一? 得到一个猜? 现简介如? h识之士斧?
首先看一DSGI*STL源代? 摘自stl_iterator.h
1: template <class _Container, class _Iterator>
2: inline insert_iterator<_Container> inserter(_Container& __x, _Iterator __i)
3: {
4: typedef typename _Container::iterator __iter;
5: return insert_iterator<_Container>(__x, __iter(__i));
6: }
令h费解的部分在W四? 请大家在看我的解释之前先想一? 我不敢保证下面解释的正确性和
全面?
解释:
我认为typename的语义是: 通知~译? 在typename后面被声明的东西是一个类? 而不是别?br>什么东?
以上例子在Linux下用G++ 2.91~译通过, l果打印"Right". 但是如果?1行的注释号去? 注释
*2? 则编译时报错, ~译器不知道COne::one_value_typeZ? 通常在模板类参数中的cd?br>实例化之后才会显露真w? 但这个CTwocd偏又要依赖一个已l存在的COne模板c? 希望能够预先
保证CTwo::two_value_type与COne::one_value属于同一cd, q是只好请typename出山, 告诉
~译? 后面的COne::one_value_type是一个已l存在于某处的类型的名字(type name), q样~译
器就可以利的工作了.
原文|址: http://blog.csdn.net/classfactory/archive/2004/08/29/87749.aspx
C++ 中的枚Dcdl承?C 语言。就像其他从 C 语言l承q来的很多特性一PC++ 枚D也有~点Q这其中最显著的莫q于作用域问题——在枚Dcd中定义的帔RQ属于定义枚丄作用域,而不属于q个枚Dcd。例如下面的CZQ?/p>
enum FileAccess {
Read = 0x1,
Write = 0x2,
};
FileAccess access = ::Read; // 正确
FileAccess access = FileAccess::Read; // 错误
C++枚D的这个特点对于习惯面向对象和作用域概늚人来说是不可接受的。首先,FileAccess::Read 昄更加W合E序员的直觉Q因Z面的枚D定义理应{h于如下的定义Q实际上Q?NET 中的枚Dcd便是如此实现的)Q?/p>
class FileAccess {
static const int Read = 0x1;
static const int Write = 0x2;
};
其次Q这D我们无法在同一个作用域中定义两个同样名U的枚D倹{也是_以下的代码是~译错误Q?/p>
enum FileAccess {
Read = 0x1,
Write = 0x2,
};
enum FileShare {
Read = 0x1, // 重定?br> Write = 0x2, // 重定?br>};
如果q一Ҏ有让你恼怒过的话Q你可能q没写过多少 C++ 代码 :-)。实际上Q在最新的 C++0x 标准草案中有关于枚D作用域问题的提案Q但最l的解决Ҏ会是怎样的就无法未卜先知了,毕竟对于?C++ q样使用q泛的语a来说QQ何特性的增删和修攚w必须十分心谨慎?/p>
当然Q我们可以用一些迂回的Ҏ来解册个问题(C++ L能给我们很多惊喜和意外)。例如,我们可以把枚丑ր放在一个结构里Qƈ使用q算W重载来D枚D的特性:
struct FileAccess {
enum __Enum {
Read = 0x1,
Write = 0x2
};
__Enum _value; // 枚D?/p>
FileAccess(int value = 0) : _value((__Enum)value) {}
FileAccess& operator=(int value) {
this->_value = (__Enum)value;
return *this;
}
operator int() const {
return this->_value;
}
};
我们现在可以按照希望的方式用这个枚丄型:
FileAccess access = FileAccess::Read;
q且Q因为我们提供了?int cd的{换运符Q因此在需?int 的地斚w可以使用它,例如 switch 语句Q?/p>
switch (access) {
case FileAccess::Read:
break;
case FileAccess::Write:
break;
}
当然我们不愿意每ơ都手工~写q样的结构。通过使用宏,我们可以很容易做到这一点:
#define DECLARE_ENUM(E) \
struct E \
{ \
public: \
E(int value = 0) : _value((__Enum)value) { \
} \
E& operator=(int value) { \
this->_value = (__Enum)value; \
return *this; \
} \
operator int() const { \
return this->_value; \
} \
\
enum __Enum {
#define END_ENUM() \
}; \
\
private: \
__Enum _value; \
};
我们现在可以按如下的方式定义前面的枚举,q且不比直接?enum 复杂多少?/p>
DECLARE_ENUM(FileAccess)
Read = 0x1,
Write = 0x2,
END_ENUM()
DECLARE_ENUM(FileShare)
Read = 0x1,
Write = 0x2,
END_ENUM()
--------------指针----------------
int a=10;
int *p=&a;
-------------指针的指?----------
int b=20;
int *p=&b;
int **p2p=&p;
-------------单数l?----------------
int c[10];//整数数组Q含?0个整数元?br>也就是说每一个元素都是整?br>
--------------指针数组--------------------
int *p[10];//指针数组Q含?0个指针元?br>也就是说每一个元素都是指?br>
--------------数组指针--------------------
int (*p)[10];//数组指针Q这个指针能够用来指?br>含有10个元素的整数数组
------------函数指针---------------------
int (*p)( ); // 指向函数的指?..q里声明了一个指针pQ该指针指向q回值是整型Q即函数cd为整型)的函敎ͼ
----------------指针函数---------------------------
int *p(int a,float b); //q回gؓ指针的函?..该函数返回指向整型变量的指针Q?/font>
卌函数的类型ؓint *, p和上例不同,他是函数名!上例中是指针Q?/font>
===========================================================================
C/C 中函数指针的含义
作者:宁
函数存放在内存的代码区域内,他们同样有地址Q我们如何能获得函数的地址呢?
假如我们有一个int test(int a)的函敎ͼ那么Q他的地址是函数的名字,q一点如同数l相同,数组的名字就是数l的起始地址?
定义一个指向函数的指针用如下的形式Q以上面的test()ZQ?
int (*fp)(int a);//q里定义了一个指向函数的指针
函数指针不能l对不能指向不同cdQ或是带不同形参的函敎ͼ在定义函数指针的时候我们很Ҏ犯如下的错误?/font>
int *fp(int a);//q里是错误的Q因为按照结合性和优先U来看就是先?)l合Q然后变成了一个返回整形指针的函数了,而不是函数指针,q一点尤光要注意!
下面我们来看一个具体的例子Q?/font>
#include <iostream>
#include <string>
using namespace std;
int test(int a);
void main(int argc,char* argv[])
{
cout<<test<<endl;//昄函数地址
int (*fp)(int a);
fp=test;//函数test的地址赋给函数学指针fp
cout<<fp(5)<<"|"<<(*fp)(10)<<endl;
//上面的输出fp(5),q是标准c 的写?(*fp)(10)q是兼容c语言的标准写?两种同意,但注意区?避免写的E式产生UL性问?
cin.get();
}
int test(int a)
{
return a;
}
typedef定义能够化函数指针的定义Q在定义一个的时候感觉不出来Q但定义多了q道方便了Q上面的代码改写成如下的形式Q?/font>
#include <iostream>
#include <string>
using namespace std;
int test(int a);
void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int a);//注意,q里不是生命函数指针,而是定义一个函数指针的cd,q个cd是自己定义的,cd名ؓfp
fp fpi;//q里利用自己定义的类型名fp定义了一个fpi的函数指?
fpi=test;
cout<<fpi(5)<<"|"<<(*fpi)(10)<<endl;
cin.get();
}
int test(int a)
{
return a;
}
函数指针同样是能够作为参C递给函数的,下面我们看个例子Q仔l阅L会发现他的用处Q稍加推理能够很方便我们q行一些复杂的~程工作?/font>
//-------------------该例以上一个例子作为基E加了修?----------------------------
#include <iostream>
#include <string>
using namespace std;
int test(int);
int test2(int (*ra)(int),int);
void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int);
fp fpi;
fpi=test;//fpi赋予test 函数的内存地址
cout<<test2(fpi,1)<<endl;//q里调用test2函数的时?q里把fpi所存储的函数地址(test的函数地址)传递了ltest2的第一个Ş?
cin.get();
}
int test(int a)
{
return a-1;
}
int test2(int (*ra)(int),int b)//q里定义了一个名字ؓra的函数指?
{
int c=ra(10) b;//在调用之?ra已指向fpi所指向的函数地址即test函数
return c;
}
利用函数指针Q我们能够构成指针数l,更明点的说法是构成指向函数的指针数l,q么说可能就Ҏ理解的多了?/font>
#include <iostream>
#include <string>
using namespace std;
void t1(){cout<<"test1";}
void t2(){cout<<"test2";}
void t3(){cout<<"test3";}
void main(int argc,char* argv[])
{
void* a[]={t1,t2,t3};
cout<<"比较t1()的内存地址和数la[0]所存储的地址是否一?<<t1<<"|"<<a[0]<<endl;
cout<<a[0]();//错误!指针数组是不能利用数l下标操作调用函数的
typedef void (*fp)();//自定义一个函数指针类?
fp b[]={t1,t2,t3}; //利用自定义类型fp把b[]定义一个指向函数的指针数组
b[0]();//现在利用指向函数的指针数l进行下标操作就能够q行函数的间接调用了;
cin.get();
}
仔细看上面的例子可能不用我多说大家也会知道是怎么一会事情了,最后我们做一个重点小l?只要Cq一?对于理解利用函数指针构成数组q行函数间接调用很Ҏ?
void* a[]={t1,t2,t3};
cout<<"比较t1()的内存地址和数la[0]所存储的地址是否一?<<t1<<"|"<<a[0]<<endl;
cout<<a[0]();//错误!指针数组是不能利用数l下标操作调用函数的
上面的这一段中的错误行,Z么不能这么调用呢Q?
前一教E我们已说的很清楚了Q但是在q里我们q是复习一下概念,指针数组元素所保存的只是个内存地址Q既然只是个内存地址׃可能q行a[0]()q样地址带括L操作Q而函数指针不同他是个例外Q函数指针只所以这么叫他就是因Z是指向函数指向内存的代码区的指针Q他被系l授予允许和()括号操作的权利,q行间接的函数调用,既然函数指针允许q么操作Q那么被定义成函数指针的数组׃定是能够相同的操作的?/font>